Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(581)

Side by Side Diff: media/midi/midi_manager_winrt.cc

Issue 2243183002: Web MIDI backend for Windows 10 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/midi/midi_manager_winrt.h"
6
7 #include <robuffer.h>
8 #include <windows.devices.enumeration.h>
9 #include <windows.devices.midi.h>
10 #include <wrl/event.h>
11
12 #include <functional>
13
14 #include "base/bind.h"
15 #include "base/containers/hash_tables.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/timer/timer.h"
19 #include "base/win/windows_version.h"
20
21 namespace media {
22 namespace midi {
23 namespace {
24
25 namespace WRL = Microsoft::WRL;
26
27 using namespace ABI::Windows::Devices::Enumeration;
28 using namespace ABI::Windows::Devices::Midi;
29 using namespace ABI::Windows::Foundation;
30 using namespace ABI::Windows::Storage::Streams;
31
32 using std::placeholders::_1;
33 using std::placeholders::_2;
Shao-Chuan Lee 2016/08/18 08:48:57 Unused, removed
34
35 template <typename InterfaceType>
36 InterfaceType* GetStatics(const base::string16& class_id) {
37 InterfaceType* ptr;
Takashi Toyoshima 2016/08/16 09:30:29 Probably com_ptr or something is better. Usually w
Shao-Chuan Lee 2016/08/18 08:48:56 Done. Also changed to using ComPtr to have ref-cou
38
39 HRESULT hr = GetActivationFactory(
40 WRL::Wrappers::HStringReference(class_id.c_str()).Get(), &ptr);
41 DCHECK(!FAILED(hr));
42
43 return ptr;
44 }
45
46 auto GetBufferFactory() {
Takashi Toyoshima 2016/08/16 09:30:29 Generally speaking, trailing return types are not
Shao-Chuan Lee 2016/08/18 08:48:56 Done. Now these factory functions return ComPtr wh
47 return GetStatics<IBufferFactory>(
48 RuntimeClass_Windows_Storage_Streams_Buffer);
49 }
50
51 auto GetDeviceInformationStatics() {
52 return GetStatics<IDeviceInformationStatics>(
53 RuntimeClass_Windows_Devices_Enumeration_DeviceInformation);
54 }
55
56 auto GetMidiInPortStatics() {
57 return GetStatics<IMidiInPortStatics>(
58 RuntimeClass_Windows_Devices_Midi_MidiInPort);
59 }
60
61 auto GetMidiOutPortStatics() {
62 return GetStatics<IMidiOutPortStatics>(
63 RuntimeClass_Windows_Devices_Midi_MidiOutPort);
64 }
65
66 template <typename T>
67 inline std::string GetIdString(T obj) {
Takashi Toyoshima 2016/08/16 09:30:29 Shall we make this "inline" compiler's decision so
Shao-Chuan Lee 2016/08/18 08:48:56 Done.
68 HSTRING hs;
Takashi Toyoshima 2016/08/16 09:30:28 "HRESULT hr" is very traditional abbreviation, but
Shao-Chuan Lee 2016/08/18 08:48:56 Using `HSTRING result' now.
69 HRESULT hr = obj->get_Id(&hs);
70 DCHECK(!FAILED(hr));
Takashi Toyoshima 2016/08/16 09:30:29 Just a question: can we assume this call should su
Shao-Chuan Lee 2016/08/18 08:48:56 HSTRING uses nullptr to represent empty strings, i
Takashi Toyoshima 2016/08/18 11:09:21 Acknowledged.
71 return base::WideToUTF8(WindowsGetStringRawBuffer(hs, nullptr));
Shao-Chuan Lee 2016/08/18 08:48:56 This is calling base::WideToUTF8(const std::wstrin
72 }
73
74 template <typename T>
Takashi Toyoshima 2016/08/16 09:30:29 same comments on the following methods.
Shao-Chuan Lee 2016/08/18 08:48:56 Done.
75 inline std::string GetDeviceIdString(T obj) {
76 HSTRING hs;
77 HRESULT hr = obj->get_DeviceId(&hs);
78 DCHECK(!FAILED(hr));
79 return base::WideToUTF8(WindowsGetStringRawBuffer(hs, nullptr));
80 }
81
82 inline std::string GetNameString(IDeviceInformation* info) {
83 HSTRING hs;
84 HRESULT hr = info->get_Name(&hs);
85 DCHECK(!FAILED(hr));
86 return base::WideToUTF8(WindowsGetStringRawBuffer(hs, nullptr));
87 }
88
89 template <typename InterfaceType>
90 struct MidiPort {
91 MidiPort() {}
92
93 uint32_t index;
94 WRL::ComPtr<InterfaceType> handle;
95 base::TimeTicks start_time;
Takashi Toyoshima 2016/08/16 09:30:29 This looks working differently from the spec.
96
97 private:
98 DISALLOW_COPY_AND_ASSIGN(MidiPort);
99 };
100
101 template <typename InterfaceType, typename RuntimeType>
102 class MidiPortManager {
103 public:
104 MidiPortManager() {}
Takashi Toyoshima 2016/08/16 09:30:29 FYI, we are allowed to use "= default" if you want
Shao-Chuan Lee 2016/08/18 08:48:56 Done.
105
106 void StartWatcher() {
107 HRESULT hr;
108
109 hr = GetDeviceInformationStatics()->CreateWatcherAqsFilter(
110 GetDeviceSelector(), &watcher_);
111 DCHECK(!FAILED(hr));
112
113 hr = watcher_->add_Added(
114 WRL::Callback<ITypedEventHandler<DeviceWatcher*, DeviceInformation*>>(
115 std::bind(&MidiPortManager::OnAdded, this, _1, _2))
116 .Get(),
117 &token_Added_);
118 DCHECK(!FAILED(hr));
119
120 hr = watcher_->add_EnumerationCompleted(
121 WRL::Callback<ITypedEventHandler<DeviceWatcher*, IInspectable*>>(
122 std::bind(&MidiPortManager::OnEnumerationCompleted, this, _1, _2))
123 .Get(),
124 &token_EnumerationCompleted_);
125 DCHECK(!FAILED(hr));
126
127 hr = watcher_->add_Removed(
128 WRL::Callback<
129 ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>>(
130 std::bind(&MidiPortManager::OnRemoved, this, _1, _2))
131 .Get(),
132 &token_Removed_);
133 DCHECK(!FAILED(hr));
134
135 hr = watcher_->add_Stopped(
136 WRL::Callback<ITypedEventHandler<DeviceWatcher*, IInspectable*>>(
137 std::bind(&MidiPortManager::OnStopped, this, _1, _2))
138 .Get(),
139 &token_Stopped_);
140 DCHECK(!FAILED(hr));
141
142 hr = watcher_->add_Updated(
143 WRL::Callback<
144 ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>>(
145 std::bind(&MidiPortManager::OnUpdated, this, _1, _2))
146 .Get(),
147 &token_Updated_);
148 DCHECK(!FAILED(hr));
149
150 hr = watcher_->Start();
151 DCHECK(!FAILED(hr));
152 }
153
154 MidiPort<InterfaceType>* GetPortByDeviceId(std::string dev_id) {
155 base::AutoLock auto_lock(ports_lock_);
156 auto it = ports_.find(dev_id);
157 if (it == ports_.end())
158 return nullptr;
159 return it->second.get();
160 }
161
162 MidiPort<InterfaceType>* GetPortByIndex(uint32_t port_index) {
163 base::AutoLock auto_lock(ports_lock_);
164 auto it = ports_.find(port_ids_[port_index]);
165 if (it == ports_.end())
166 return nullptr;
167 return it->second.get();
168 }
169
170 // DeviceWatcher callbacks:
171 HRESULT OnAdded(IDeviceWatcher* watcher, IDeviceInformation* info) {
172 // TODO(shaochuan): Disable Microsoft GS Wavetable Synth due to security
Takashi Toyoshima 2016/08/16 09:30:29 Do you know if we can identify software virtual po
Shao-Chuan Lee 2016/08/18 08:48:57 The MS synth can be identified using WinRT MidiSyn
Takashi Toyoshima 2016/08/18 11:09:21 Acknowledged.
173 // reasons. https://bugs.chromium.org/p/project-zero/issues/detail?id=454
174
175 HSTRING dev_id_hs;
Takashi Toyoshima 2016/08/16 09:30:29 Can you use GetIdString you defined?
Shao-Chuan Lee 2016/08/18 08:48:57 This HSTRING is required for RegisterGetPortFromId
Takashi Toyoshima 2016/08/18 11:09:21 Ah, I see. I misunderstood these lines.
176 HRESULT hr = info->get_Id(&dev_id_hs);
177 DCHECK(!FAILED(hr));
178
179 std::string dev_id =
180 base::WideToUTF8(WindowsGetStringRawBuffer(dev_id_hs, nullptr));
Shao-Chuan Lee 2016/08/18 08:48:56 Now using GetIdString to reuse nullptr checking co
181
182 {
183 base::AutoLock auto_lock(ports_lock_);
184 port_names_[dev_id] = GetNameString(info);
185 }
186
187 WRL::ComPtr<IAsyncOperation<RuntimeType*>> async_op;
188
189 RegisterGetPortFromIdAsync(&async_op, dev_id_hs);
190
191 hr = async_op->put_Completed(
192 WRL::Callback<IAsyncOperationCompletedHandler<RuntimeType*>>(
193 std::bind(&MidiPortManager::OnCompletedGetPortFromIdAsync, this, _1,
194 _2))
195 .Get());
196 DCHECK(!FAILED(hr));
197
198 {
199 base::AutoLock auto_lock(async_ops_lock_);
200 async_ops_.insert(std::move(async_op));
201 }
202
203 return S_OK;
204 }
205
206 HRESULT OnEnumerationCompleted(IDeviceWatcher* watcher, IInspectable* insp) {
207 // TODO(shaochuan)
Takashi Toyoshima 2016/08/16 09:30:28 What's missing here? At least, we should complete
Shao-Chuan Lee 2016/08/18 08:48:56 Should CompleteInitialization() be moved here? I w
Takashi Toyoshima 2016/08/18 11:09:21 This isn't a problem for two reasons. - MidiManag
208 return S_OK;
209 }
210
211 HRESULT OnRemoved(IDeviceWatcher* watcher, IDeviceInformationUpdate* update) {
212 MidiPort<InterfaceType>* port = GetPortByDeviceId(GetIdString(update));
213 DCHECK(port != nullptr);
214
215 SetPortState(port->index, MIDI_PORT_DISCONNECTED);
216
217 port->handle = nullptr;
218
219 return S_OK;
220 }
221
222 HRESULT OnStopped(IDeviceWatcher* watcher, IInspectable* insp) {
223 // TODO(shaochuan)
Takashi Toyoshima 2016/08/16 09:30:29 ditto
Shao-Chuan Lee 2016/08/18 08:48:56 Does nothing for now, leaving as a placeholder for
224 return S_OK;
225 }
226
227 HRESULT OnUpdated(IDeviceWatcher* watcher, IDeviceInformationUpdate* update) {
228 // TODO(shaochuan)
Takashi Toyoshima 2016/08/16 09:30:29 ditto
Shao-Chuan Lee 2016/08/18 08:48:56 Should update device information here, will check
229 return S_OK;
230 }
231
232 private:
233 HRESULT OnCompletedGetPortFromIdAsync(IAsyncOperation<RuntimeType*>* async_op,
234 AsyncStatus status) {
235 const auto now = base::TimeTicks::Now();
236
237 InterfaceType* handle;
238 HRESULT hr = async_op->GetResults(&handle);
239 DCHECK(!FAILED(hr));
240
241 RegisterOnMessageReceived(handle);
242
243 std::string dev_id = GetDeviceIdString(handle);
244
245 MidiPort<InterfaceType>* port = GetPortByDeviceId(dev_id);
246
247 if (port == nullptr) {
248 base::AutoLock auto_lock(ports_lock_);
249
250 // TODO(shaochuan)
Takashi Toyoshima 2016/08/16 09:30:28 Clear comments for this TODO?
Shao-Chuan Lee 2016/08/18 08:48:56 Done.
251 AddPort(MidiPortInfo(dev_id, std::string("Manufacturer"),
252 port_names_[dev_id], std::string("DriverVersion"),
253 MIDI_PORT_OPENED));
254
255 port = new MidiPort<InterfaceType>;
256 port->index = static_cast<uint32_t>(port_ids_.size());
257
258 ports_[dev_id].reset(port);
259 port_ids_.push_back(dev_id);
260 } else {
261 SetPortState(port->index, MIDI_PORT_CONNECTED);
262 }
263
264 port->handle = handle;
265 port->start_time = now;
266
267 {
268 base::AutoLock auto_lock(async_ops_lock_);
269 auto it = async_ops_.find(async_op);
270 DCHECK(it != async_ops_.end());
271 async_ops_.erase(it);
272 }
273
274 return S_OK;
275 }
276
277 // Implemented by child classes to call corresponding input/output methods.
Takashi Toyoshima 2016/08/16 09:30:28 "to return a corresponding device selector for inp
Shao-Chuan Lee 2016/08/18 08:48:56 This comment was meant to describe all the followi
278 virtual HSTRING GetDeviceSelector() = 0;
279
280 virtual void RegisterGetPortFromIdAsync(
Takashi Toyoshima 2016/08/16 09:30:29 Also can you add some comments for other virtual m
Shao-Chuan Lee 2016/08/18 08:48:56 Done.
281 IAsyncOperation<RuntimeType*>** p_async_op,
282 HSTRING dev_id) = 0;
283
284 virtual void RegisterOnMessageReceived(InterfaceType* handle) = 0;
285
286 virtual void AddPort(MidiPortInfo info) = 0;
287
288 virtual void SetPortState(uint32_t port_index, MidiPortState state) = 0;
289
290 WRL::ComPtr<IDeviceWatcher> watcher_;
291 EventRegistrationToken token_Added_, token_EnumerationCompleted_,
292 token_Removed_, token_Stopped_, token_Updated_;
293
294 base::Lock ports_lock_;
Takashi Toyoshima 2016/08/16 09:30:29 Can you explain (== add comments) why locks are ne
Shao-Chuan Lee 2016/08/18 08:48:56 Locks are required since fields are manipulated fr
295 base::hash_map<std::string, std::unique_ptr<MidiPort<InterfaceType>>>
296 ports_; // GUARDED_BY(ports_lock_)
297 std::vector<std::string> port_ids_; // GUARDED_BY(ports_lock_)
298 base::hash_map<std::string, std::string>
299 port_names_; // GUARDED_BY(ports_lock_)
300
301 base::Lock async_ops_lock_;
302 std::set<WRL::ComPtr<IAsyncOperation<RuntimeType*>>>
303 async_ops_; // GUARDED_BY(async_ops_lock_)
304 };
305
306 } // namespace
307
308 class MidiManagerWinrt::MidiInPortManager final
309 : public MidiPortManager<IMidiInPort, MidiInPort> {
310 public:
311 MidiInPortManager(MidiManagerWinrt* midi_manager)
312 : midi_manager_(midi_manager) {}
313
314 private:
315 // MidiPortManager overrides:
316 HSTRING GetDeviceSelector() override {
317 HSTRING selector = nullptr;
318 HRESULT hr = GetMidiInPortStatics()->GetDeviceSelector(&selector);
319 DCHECK(!FAILED(hr));
320 return selector;
321 }
322
323 void RegisterGetPortFromIdAsync(IAsyncOperation<MidiInPort*>** p_async_op,
324 HSTRING dev_id) override {
325 HRESULT hr = GetMidiInPortStatics()->FromIdAsync(dev_id, p_async_op);
326 DCHECK(!FAILED(hr));
327 }
328
329 void RegisterOnMessageReceived(IMidiInPort* handle) override {
330 base::AutoLock auto_lock(tokens_lock_);
331 EventRegistrationToken& token = tokens_[GetDeviceIdString(handle)];
332
333 handle->add_MessageReceived(
334 WRL::Callback<
335 ITypedEventHandler<MidiInPort*, MidiMessageReceivedEventArgs*>>(
336 std::bind(&MidiInPortManager::OnMessageReceived, this, _1, _2))
337 .Get(),
338 &token);
339 }
340
341 void AddPort(MidiPortInfo info) { midi_manager_->AddInputPort(info); }
342
343 void SetPortState(uint32_t port_index, MidiPortState state) {
344 midi_manager_->SetInputPortState(port_index, state);
Takashi Toyoshima 2016/08/16 09:30:29 Probably, this call should be called on the I/O th
Shao-Chuan Lee 2016/08/18 08:48:56 This is currently called on the OS callback thread
Takashi Toyoshima 2016/08/18 11:09:21 Basically, if you can not find a clear comment, it
345 }
346
347 // Callback on receiving MIDI input message.
348 HRESULT OnMessageReceived(IMidiInPort* handle,
349 IMidiMessageReceivedEventArgs* args) {
350 MidiPort<IMidiInPort>* port = GetPortByDeviceId(GetDeviceIdString(handle));
351 DCHECK(port != nullptr);
352
353 WRL::ComPtr<IMidiMessage> message;
354 HRESULT hr = args->get_Message(&message);
355 DCHECK(!FAILED(hr));
356
357 WRL::ComPtr<IBuffer> buffer;
358 hr = message->get_RawData(&buffer);
359 DCHECK(!FAILED(hr));
360
361 // Use BufferByteAccess object to access buffer memory directly.
362 WRL::ComPtr<IInspectable> insp(
Takashi Toyoshima 2016/08/16 09:30:29 Shall we have a clear name?
Shao-Chuan Lee 2016/08/18 08:48:56 Moved to a separate function, using `buffer_byte_a
363 reinterpret_cast<IInspectable*>(buffer.Get()));
364 WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bba;
Takashi Toyoshima 2016/08/16 09:30:29 ditto
Shao-Chuan Lee 2016/08/18 08:48:56 Done.
365 hr = insp.As(&bba);
366 DCHECK(!FAILED(hr));
367
368 uint8_t* data_arr = nullptr;
Takashi Toyoshima 2016/08/16 09:30:29 ditto
Shao-Chuan Lee 2016/08/18 08:48:56 Using `p_buffer_data'.
369 hr = bba->Buffer(reinterpret_cast<byte**>(&data_arr));
Shao-Chuan Lee 2016/08/18 08:48:56 Removing reinterpret_cast here since byte** is com
370 DCHECK(!FAILED(hr));
371
372 uint32_t len;
Takashi Toyoshima 2016/08/16 09:30:29 probably we may also want to avoid the name like l
Shao-Chuan Lee 2016/08/18 08:48:57 Using `data_length'.
373 hr = buffer->get_Length(&len);
374 DCHECK(!FAILED(hr));
375 DCHECK(len != 0);
376
377 std::vector<uint8_t> data(data_arr, data_arr + len);
378
379 // Time since port opened in 100-nanosecond units.
380 TimeSpan time_span;
381 hr = message->get_Timestamp(&time_span);
382 DCHECK(!FAILED(hr));
383
384 midi_manager_->ReceiveMidiData(
385 port->index, &data[0], data.size(),
386 port->start_time +
Takashi Toyoshima 2016/08/16 09:30:29 Can we check if how much start_time+time_span can
Shao-Chuan Lee 2016/08/18 08:48:57 message->get_Timestamp() returns "the duration fro
387 base::TimeDelta::FromMicroseconds(time_span.Duration / 10));
388
389 return S_OK;
390 }
391
392 MidiManagerWinrt* midi_manager_;
393
394 base::Lock tokens_lock_;
395 base::hash_map<std::string, EventRegistrationToken>
396 tokens_; // GUARDED_BY(tokens_lock_)
397
398 DISALLOW_COPY_AND_ASSIGN(MidiInPortManager);
399 };
400
401 class MidiManagerWinrt::MidiOutPortManager final
402 : public MidiPortManager<IMidiOutPort, IMidiOutPort> {
403 public:
404 MidiOutPortManager(MidiManagerWinrt* midi_manager)
405 : midi_manager_(midi_manager) {}
406
407 private:
408 // MidiPortManager overrides:
409 HSTRING GetDeviceSelector() override {
410 HSTRING selector = nullptr;
411 HRESULT hr = GetMidiOutPortStatics()->GetDeviceSelector(&selector);
412 DCHECK(!FAILED(hr));
413 return selector;
414 }
415
416 void RegisterGetPortFromIdAsync(IAsyncOperation<IMidiOutPort*>** p_async_op,
417 HSTRING dev_id) override {
418 HRESULT hr = GetMidiOutPortStatics()->FromIdAsync(dev_id, p_async_op);
419 DCHECK(!FAILED(hr));
420 }
421
422 void RegisterOnMessageReceived(IMidiOutPort* handle) override {}
423
424 void AddPort(MidiPortInfo info) { midi_manager_->AddOutputPort(info); }
425
426 void SetPortState(uint32_t port_index, MidiPortState state) {
427 midi_manager_->SetOutputPortState(port_index, state);
428 }
429
430 MidiManagerWinrt* midi_manager_;
431
432 DISALLOW_COPY_AND_ASSIGN(MidiOutPortManager);
433 };
434
435 MidiManagerWinrt::MidiManagerWinrt() : com_thread_("Windows MIDI COM Thread") {}
436
437 MidiManagerWinrt::~MidiManagerWinrt() {}
438
439 void MidiManagerWinrt::StartInitialization() {
440 DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN10);
441
442 scheduler_.reset(new MidiScheduler(this));
443
444 com_thread_.init_com_with_mta(true);
445 com_thread_.Start();
446
447 com_thread_.message_loop()->PostTask(
448 FROM_HERE, base::Bind(&MidiManagerWinrt::InitializeOnComThread,
449 base::Unretained(this)));
450
451 CompleteInitialization(Result::OK);
452 }
453
454 void MidiManagerWinrt::Finalize() {
455 // TODO(shaochuan): Check if everything is destructed gracefully.
456 port_manager_in_.reset();
457 port_manager_out_.reset();
458
459 scheduler_.reset();
460
461 com_thread_.Stop();
462 }
463
464 void MidiManagerWinrt::DispatchSendMidiData(MidiManagerClient* client,
465 uint32_t port_index,
466 const std::vector<uint8_t>& data,
467 double timestamp) {
468 com_thread_.message_loop()->PostTask(
469 FROM_HERE,
470 base::Bind(&MidiManagerWinrt::PostSendDataTaskOnComThread,
471 base::Unretained(this), client, port_index, data, timestamp));
472 }
473
474 void MidiManagerWinrt::AssertOnComThread() {
475 DCHECK_EQ(com_thread_.GetThreadId(), base::PlatformThread::CurrentId());
Takashi Toyoshima 2016/08/16 09:30:29 Ah, you may want to replace this with the thread c
Takashi Toyoshima 2016/08/18 11:09:21 not fixed yet?
476 }
477
478 void MidiManagerWinrt::InitializeOnComThread() {
479 AssertOnComThread();
480
481 port_manager_in_.reset(new MidiInPortManager(this));
482 port_manager_out_.reset(new MidiOutPortManager(this));
483
484 port_manager_in_->StartWatcher();
485 port_manager_out_->StartWatcher();
486 }
487
488 void MidiManagerWinrt::PostSendDataTaskOnComThread(
489 MidiManagerClient* client,
490 uint32_t port_index,
491 const std::vector<uint8_t>& data,
492 double timestamp) {
493 AssertOnComThread();
494
495 scheduler_->PostSendDataTask(
496 client, data.size(), timestamp,
497 base::Bind(&MidiManagerWinrt::SendOnComThread, base::Unretained(this),
498 port_index, data));
499 }
500
501 void MidiManagerWinrt::SendOnComThread(uint32_t port_index,
502 const std::vector<uint8_t>& data) {
503 AssertOnComThread();
504
505 WRL::ComPtr<IBuffer> buffer;
506 HRESULT hr =
507 GetBufferFactory()->Create(static_cast<UINT32>(data.size()), &buffer);
508 DCHECK(!FAILED(hr));
509
510 hr = buffer->put_Length(static_cast<UINT32>(data.size()));
511 DCHECK(!FAILED(hr));
512
513 // Use BufferByteAccess object to access buffer memory directly.
Takashi Toyoshima 2016/08/16 09:30:29 Clear names.
Shao-Chuan Lee 2016/08/18 08:48:56 Done.
514 WRL::ComPtr<IInspectable> insp(reinterpret_cast<IInspectable*>(buffer.Get()));
515 WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bba;
516 hr = insp.As(&bba);
517 DCHECK(!FAILED(hr));
518
519 uint8_t* data_arr = nullptr;
520 hr = bba->Buffer(reinterpret_cast<byte**>(&data_arr));
Shao-Chuan Lee 2016/08/18 08:48:56 ditto
521 DCHECK(!FAILED(hr));
522
523 std::copy(data.begin(), data.end(), data_arr);
524
525 MidiPort<IMidiOutPort>* port = port_manager_out_->GetPortByIndex(port_index);
526 DCHECK(port != nullptr);
527
528 hr = port->handle->SendBuffer(buffer.Get());
529 DCHECK(!FAILED(hr));
530 }
531
532 MidiManager* MidiManager::Create() {
533 return new MidiManagerWinrt();
534 }
535
536 } // namespace midi
537 } // namespace media
OLDNEW
« media/midi/midi_manager_winrt.h ('K') | « media/midi/midi_manager_winrt.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698