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

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: rebase, fixup Created 4 years, 3 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 "base/bind.h"
13 #include "base/containers/hash_tables.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "base/timer/timer.h"
18 #include "base/win/windows_version.h"
19
20 namespace media {
21 namespace midi {
22 namespace {
23
24 namespace WRL = Microsoft::WRL;
25
26 using namespace ABI::Windows::Devices::Enumeration;
27 using namespace ABI::Windows::Devices::Midi;
28 using namespace ABI::Windows::Foundation;
29 using namespace ABI::Windows::Storage::Streams;
30
31 // Factory functions that activate and create WinRT components. The caller takes
32 // ownership of the returning ComPtr.
33 template <typename InterfaceType, base::char16 const* runtime_class_id>
34 WRL::ComPtr<InterfaceType> WrlStaticsFactory() {
35 WRL::ComPtr<InterfaceType> com_ptr;
36
37 HRESULT hr = GetActivationFactory(
38 WRL::Wrappers::HStringReference(runtime_class_id).Get(), &com_ptr);
39 DCHECK(SUCCEEDED(hr));
40
41 return com_ptr;
42 }
43
44 WRL::ComPtr<IBufferFactory> GetBufferFactory() {
45 return WrlStaticsFactory<IBufferFactory,
46 RuntimeClass_Windows_Storage_Streams_Buffer>();
47 }
48
49 WRL::ComPtr<IDeviceInformationStatics> GetDeviceInformationStatics() {
50 return WrlStaticsFactory<
51 IDeviceInformationStatics,
52 RuntimeClass_Windows_Devices_Enumeration_DeviceInformation>();
53 }
54
55 template <typename T, HRESULT (T::*method)(HSTRING*)>
56 std::string GetStringFromObjectMethod(T* obj) {
57 HSTRING result;
58 HRESULT hr = (obj->*method)(&result);
59 DCHECK(SUCCEEDED(hr));
60
61 const base::char16* buffer = WindowsGetStringRawBuffer(result, nullptr);
62 if (buffer)
63 return base::WideToUTF8(buffer);
64 return std::string();
65 }
66
67 template <typename T>
68 std::string GetIdString(T* obj) {
69 return GetStringFromObjectMethod<T, &T::get_Id>(obj);
70 }
71
72 template <typename T>
73 std::string GetDeviceIdString(T* obj) {
74 return GetStringFromObjectMethod<T, &T::get_DeviceId>(obj);
75 }
76
77 std::string GetNameString(IDeviceInformation* info) {
78 return GetStringFromObjectMethod<IDeviceInformation,
79 &IDeviceInformation::get_Name>(info);
80 }
81
82 uint8_t* GetPointerToBufferData(IBuffer* buffer) {
83 WRL::ComPtr<IInspectable> inspectable(
84 reinterpret_cast<IInspectable*>(buffer));
85 WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> buffer_byte_access;
86
87 HRESULT hr = inspectable.As(&buffer_byte_access);
88 DCHECK(SUCCEEDED(hr));
89
90 uint8_t* ptr = nullptr;
91 hr = buffer_byte_access->Buffer(&ptr);
92 DCHECK(SUCCEEDED(hr));
93
94 // Lifetime of the pointing buffer is controlled by the buffer object.
95 return ptr;
96 }
97
98 template <typename InterfaceType>
99 struct MidiPort {
100 MidiPort() = default;
101
102 uint32_t index;
103 WRL::ComPtr<InterfaceType> handle;
104 base::TimeTicks start_time;
105
106 private:
107 DISALLOW_COPY_AND_ASSIGN(MidiPort);
108 };
109
110 template <typename InterfaceType,
111 typename RuntimeType,
112 typename StaticsInterfaceType,
113 base::char16 const* runtime_class_id>
114 class MidiPortManager {
115 public:
116 // MidiPortManager instances should be constructed on the COM thread.
117 MidiPortManager(MidiManagerWinrt* midi_manager)
118 : midi_manager_(midi_manager),
119 task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
120
121 void StartWatcher() {
122 DCHECK(thread_checker_.CalledOnValidThread());
123
124 HRESULT hr;
125
126 midi_port_statics_ =
127 WrlStaticsFactory<StaticsInterfaceType, runtime_class_id>();
128
129 HSTRING device_selector = nullptr;
130 hr = midi_port_statics_->GetDeviceSelector(&device_selector);
131 DCHECK(SUCCEEDED(hr));
Takashi Toyoshima 2016/08/23 08:09:37 Probably, TODO is needed so that CompleteInitializ
Shao-Chuan Lee 2016/08/24 08:50:31 Now returning Result::INITIALIZATION_ERROR if any
132
133 hr = GetDeviceInformationStatics()->CreateWatcherAqsFilter(device_selector,
134 &watcher_);
135 DCHECK(SUCCEEDED(hr));
136
137 // Register callbacks to WinRT that post state-modifying jobs back to COM
138 // thread. |weak_ptr| and |task_runner| are captured by lambda callbacks for
139 // posting jobs. Note that WinRT callback arguments should not be passed
140 // outside the callback since the pointers may be unavailable afterwards.
141 base::WeakPtr<MidiPortManager> weak_ptr = GetWeakPtrFromFactory();
142 scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_;
143
144 hr = watcher_->add_Added(
145 WRL::Callback<ITypedEventHandler<DeviceWatcher*, DeviceInformation*>>(
146 [weak_ptr, task_runner](IDeviceWatcher* watcher,
147 IDeviceInformation* info) {
148 std::string dev_id = GetIdString(info),
149 dev_name = GetNameString(info);
150
151 task_runner->PostTask(
152 FROM_HERE, base::Bind(&MidiPortManager::OnAdded, weak_ptr,
153 dev_id, dev_name));
154
155 return S_OK;
156 })
157 .Get(),
158 &token_Added_);
159 DCHECK(SUCCEEDED(hr));
160
161 hr = watcher_->add_EnumerationCompleted(
162 WRL::Callback<ITypedEventHandler<DeviceWatcher*, IInspectable*>>(
163 [weak_ptr, task_runner](IDeviceWatcher* watcher,
164 IInspectable* insp) {
165 task_runner->PostTask(
166 FROM_HERE,
167 base::Bind(&MidiPortManager::OnEnumerationCompleted,
168 weak_ptr));
169
170 return S_OK;
171 })
172 .Get(),
173 &token_EnumerationCompleted_);
174 DCHECK(SUCCEEDED(hr));
175
176 hr = watcher_->add_Removed(
177 WRL::Callback<
178 ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>>(
179 [weak_ptr, task_runner](IDeviceWatcher* watcher,
180 IDeviceInformationUpdate* update) {
181 std::string dev_id = GetIdString(update);
182
183 task_runner->PostTask(
184 FROM_HERE,
185 base::Bind(&MidiPortManager::OnRemoved, weak_ptr, dev_id));
186
187 return S_OK;
188 })
189 .Get(),
190 &token_Removed_);
191 DCHECK(SUCCEEDED(hr));
192
193 hr = watcher_->add_Stopped(
194 WRL::Callback<ITypedEventHandler<DeviceWatcher*, IInspectable*>>(
195 [](IDeviceWatcher* watcher, IInspectable* insp) {
196 // Placeholder, does nothing for now.
197 return S_OK;
198 })
199 .Get(),
200 &token_Stopped_);
201 DCHECK(SUCCEEDED(hr));
202
203 hr = watcher_->add_Updated(
204 WRL::Callback<
205 ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>>(
206 [](IDeviceWatcher* watcher, IDeviceInformationUpdate* update) {
207 // TODO(shaochuan): Check for fields to be updated here.
208 return S_OK;
209 })
210 .Get(),
211 &token_Updated_);
212 DCHECK(SUCCEEDED(hr));
213
214 hr = watcher_->Start();
215 DCHECK(SUCCEEDED(hr));
216 }
217
218 ~MidiPortManager() {
219 DCHECK(thread_checker_.CalledOnValidThread());
220
221 watcher_->remove_Added(token_Added_);
222 watcher_->remove_EnumerationCompleted(token_EnumerationCompleted_);
223 watcher_->remove_Removed(token_Removed_);
224 watcher_->remove_Stopped(token_Stopped_);
225 watcher_->remove_Updated(token_Updated_);
226
227 watcher_->Stop();
228 }
229
230 MidiPort<InterfaceType>* GetPortByDeviceId(std::string dev_id) {
231 DCHECK(thread_checker_.CalledOnValidThread());
232
233 auto it = ports_.find(dev_id);
234 if (it == ports_.end())
235 return nullptr;
236 return it->second.get();
237 }
238
239 MidiPort<InterfaceType>* GetPortByIndex(uint32_t port_index) {
240 DCHECK(thread_checker_.CalledOnValidThread());
241
242 auto it = ports_.find(port_ids_[port_index]);
243 if (it == ports_.end())
244 return nullptr;
245 return it->second.get();
246 }
247
248 protected:
249 // The owning MidiManagerWinrt.
Takashi Toyoshima 2016/08/23 08:09:38 "owning" sounds confusing here. Probably, you need
Shao-Chuan Lee 2016/08/24 08:50:31 Done.
250 MidiManagerWinrt* midi_manager_;
251
252 // Task runner of the COM thread.
253 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
254
255 // Ensures all methods are called on the COM thread.
256 base::ThreadChecker thread_checker_;
257
258 private:
259 // DeviceWatcher callbacks:
260 void OnAdded(std::string dev_id, std::string dev_name) {
261 DCHECK(thread_checker_.CalledOnValidThread());
262
263 // TODO(shaochuan): Disable Microsoft GS Wavetable Synth due to security
264 // reasons. http://crbug.com/499279
265
266 port_names_[dev_id] = dev_name;
Takashi Toyoshima 2016/08/23 08:09:38 question: is |dev_id| unique and persistent ID for
Shao-Chuan Lee 2016/08/24 08:50:31 I'm using device IDs provided by WinRT, like this:
Takashi Toyoshima 2016/08/25 06:09:44 Is this a combination of bus address like thing an
267
268 base::string16 dev_id_string16 = base::UTF8ToWide(dev_id);
269 HSTRING dev_id_hstring;
270 HRESULT hr = WindowsCreateString(
271 dev_id_string16.c_str(), static_cast<UINT32>(dev_id_string16.length()),
272 &dev_id_hstring);
273 DCHECK(SUCCEEDED(hr));
274
275 WRL::ComPtr<IAsyncOperation<RuntimeType*>> async_op;
276
277 hr = midi_port_statics_->FromIdAsync(dev_id_hstring, &async_op);
278 DCHECK(SUCCEEDED(hr));
279
280 WindowsDeleteString(dev_id_hstring);
281 dev_id_hstring = nullptr;
282
283 base::WeakPtr<MidiPortManager> weak_ptr = GetWeakPtrFromFactory();
284 scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_;
285
286 hr = async_op->put_Completed(
287 WRL::Callback<IAsyncOperationCompletedHandler<RuntimeType*>>(
288 [weak_ptr, task_runner](IAsyncOperation<RuntimeType*>* async_op,
289 AsyncStatus status) {
290 // TODO(shaochuan): Check if port open time is accurate.
291 const auto now = base::TimeTicks::Now();
292
293 InterfaceType* handle;
294 HRESULT hr = async_op->GetResults(&handle);
295 DCHECK(SUCCEEDED(hr));
296
297 // |async_op| is owned by |async_ops_|, safe to pass outside.
298 task_runner->PostTask(
299 FROM_HERE,
300 base::Bind(&MidiPortManager::OnCompletedGetPortFromIdAsync,
301 weak_ptr, handle, now, async_op));
302
303 return S_OK;
304 })
305 .Get());
306 DCHECK(SUCCEEDED(hr));
307
308 // Keep a reference to incompleted |async_op| to ensure lifetime.
309 async_ops_.insert(std::move(async_op));
310 }
311
312 void OnEnumerationCompleted() {
313 DCHECK(thread_checker_.CalledOnValidThread());
314
315 midi_manager_->OnPortManagerReady();
316 }
317
318 void OnRemoved(std::string dev_id) {
319 DCHECK(thread_checker_.CalledOnValidThread());
320
321 MidiPort<InterfaceType>* port = GetPortByDeviceId(dev_id);
322 DCHECK(port != nullptr);
323
324 SetPortState(port->index, MIDI_PORT_DISCONNECTED);
325
326 port->handle = nullptr;
327 }
328
329 void OnCompletedGetPortFromIdAsync(InterfaceType* handle,
330 base::TimeTicks start_time,
331 IAsyncOperation<RuntimeType*>* async_op) {
332 DCHECK(thread_checker_.CalledOnValidThread());
Takashi Toyoshima 2016/08/23 08:09:38 Probably this method may run after OnEnumerationCo
Shao-Chuan Lee 2016/08/24 08:50:31 Done, now OnPortManagerReady() is called after all
333
334 RegisterOnMessageReceived(handle);
335
336 std::string dev_id = GetDeviceIdString(handle);
337
338 MidiPort<InterfaceType>* port = GetPortByDeviceId(dev_id);
339
340 if (port == nullptr) {
341 // TODO(shaochuan): Fill in manufacturer and driver version.
342 AddPort(MidiPortInfo(dev_id, std::string("Manufacturer"),
343 port_names_[dev_id], std::string("DriverVersion"),
344 MIDI_PORT_OPENED));
345
346 port = new MidiPort<InterfaceType>;
347 port->index = static_cast<uint32_t>(port_ids_.size());
348
349 ports_[dev_id].reset(port);
350 port_ids_.push_back(dev_id);
351 } else {
352 SetPortState(port->index, MIDI_PORT_CONNECTED);
353 }
354
355 port->handle = handle;
356 port->start_time = start_time;
357
358 // Remove reference to completed |async_op|.
359 auto it = async_ops_.find(async_op);
360 DCHECK(it != async_ops_.end());
361 async_ops_.erase(it);
362 }
363
364 // Overrided by MidiInPortManager to listen to input ports.
365 virtual void RegisterOnMessageReceived(InterfaceType* handle) {}
366
367 // Calls midi_manager_->Add{Input,Output}Port.
368 virtual void AddPort(MidiPortInfo info) = 0;
369
370 // Calls midi_manager_->Set{Input,Output}PortState.
371 virtual void SetPortState(uint32_t port_index, MidiPortState state) = 0;
372
373 // WeakPtrFactory has to be declared in derived class, use this method to
374 // retrieve upcasted WeakPtr for posting tasks.
375 virtual base::WeakPtr<MidiPortManager> GetWeakPtrFromFactory() = 0;
376
377 // Midi{In,Out}PortStatics instance.
378 WRL::ComPtr<StaticsInterfaceType> midi_port_statics_;
379
380 // DeviceWatcher instance and event registration tokens for unsubscribing
381 // events in destructor.
382 WRL::ComPtr<IDeviceWatcher> watcher_;
383 EventRegistrationToken token_Added_, token_EnumerationCompleted_,
384 token_Removed_, token_Stopped_, token_Updated_;
385
386 // All manipulations to these fields should be done on COM thread.
387 base::hash_map<std::string, std::unique_ptr<MidiPort<InterfaceType>>> ports_;
388 std::vector<std::string> port_ids_;
389 base::hash_map<std::string, std::string> port_names_;
390
391 // Keeps AsyncOperation objects before the operation completes.
392 std::set<WRL::ComPtr<IAsyncOperation<RuntimeType*>>> async_ops_;
393 };
394
395 } // namespace
396
397 class MidiManagerWinrt::MidiInPortManager final
398 : public MidiPortManager<IMidiInPort,
399 MidiInPort,
400 IMidiInPortStatics,
401 RuntimeClass_Windows_Devices_Midi_MidiInPort> {
402 public:
403 MidiInPortManager(MidiManagerWinrt* midi_manager)
404 : MidiPortManager(midi_manager), weak_factory_(this) {}
405
406 private:
407 // MidiPortManager overrides:
408 void RegisterOnMessageReceived(IMidiInPort* handle) override {
409 DCHECK(thread_checker_.CalledOnValidThread());
410
411 EventRegistrationToken& token = tokens_[GetDeviceIdString(handle)];
412
413 base::WeakPtr<MidiInPortManager> weak_ptr = weak_factory_.GetWeakPtr();
414 scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_;
415
416 handle->add_MessageReceived(
417 WRL::Callback<
418 ITypedEventHandler<MidiInPort*, MidiMessageReceivedEventArgs*>>(
419 [weak_ptr, task_runner](IMidiInPort* handle,
420 IMidiMessageReceivedEventArgs* args) {
421 std::string dev_id = GetDeviceIdString(handle);
422
423 WRL::ComPtr<IMidiMessage> message;
424 HRESULT hr = args->get_Message(&message);
425 DCHECK(SUCCEEDED(hr));
426
427 WRL::ComPtr<IBuffer> buffer;
428 hr = message->get_RawData(&buffer);
429 DCHECK(SUCCEEDED(hr));
430
431 uint8_t* p_buffer_data = GetPointerToBufferData(buffer.Get());
432
433 uint32_t data_length;
434 hr = buffer->get_Length(&data_length);
435 DCHECK(SUCCEEDED(hr));
436 DCHECK(data_length != 0);
437
438 std::vector<uint8_t> data(p_buffer_data,
439 p_buffer_data + data_length);
440
441 // Time since port opened in 100-nanosecond units.
442 TimeSpan time_span;
443 hr = message->get_Timestamp(&time_span);
444 DCHECK(SUCCEEDED(hr));
445
446 task_runner->PostTask(
447 FROM_HERE,
448 base::Bind(&MidiInPortManager::OnMessageReceived, weak_ptr,
449 dev_id, data, base::TimeDelta::FromMicroseconds(
450 time_span.Duration / 10)));
451
452 return S_OK;
453 })
454 .Get(),
455 &token);
456 }
457
458 void AddPort(MidiPortInfo info) final { midi_manager_->AddInputPort(info); }
459
460 void SetPortState(uint32_t port_index, MidiPortState state) final {
461 midi_manager_->SetInputPortState(port_index, state);
462 }
463
464 base::WeakPtr<MidiPortManager> GetWeakPtrFromFactory() final {
465 DCHECK(thread_checker_.CalledOnValidThread());
466
467 return weak_factory_.GetWeakPtr();
468 }
469
470 // Callback on receiving MIDI input message.
471 void OnMessageReceived(std::string dev_id,
472 std::vector<uint8_t> data,
473 base::TimeDelta time_since_start) {
474 DCHECK(thread_checker_.CalledOnValidThread());
475
476 MidiPort<IMidiInPort>* port = GetPortByDeviceId(dev_id);
477 DCHECK(port != nullptr);
Takashi Toyoshima 2016/08/23 08:09:38 DCHECK_NE or just DCHECK(port)?
Shao-Chuan Lee 2016/08/24 08:50:31 Done.
478
479 midi_manager_->ReceiveMidiData(port->index, &data[0], data.size(),
480 port->start_time + time_since_start);
481 }
482
483 // Event tokens for input message received events.
484 base::hash_map<std::string, EventRegistrationToken> tokens_;
485
486 // Last member to ensure destructed first.
487 base::WeakPtrFactory<MidiInPortManager> weak_factory_;
488
489 DISALLOW_COPY_AND_ASSIGN(MidiInPortManager);
490 };
491
492 class MidiManagerWinrt::MidiOutPortManager final
493 : public MidiPortManager<IMidiOutPort,
494 IMidiOutPort,
495 IMidiOutPortStatics,
496 RuntimeClass_Windows_Devices_Midi_MidiOutPort> {
497 public:
498 MidiOutPortManager(MidiManagerWinrt* midi_manager)
499 : MidiPortManager(midi_manager), weak_factory_(this) {}
500
501 private:
502 // MidiPortManager overrides:
503 void AddPort(MidiPortInfo info) final { midi_manager_->AddOutputPort(info); }
504
505 void SetPortState(uint32_t port_index, MidiPortState state) final {
506 midi_manager_->SetOutputPortState(port_index, state);
507 }
508
509 base::WeakPtr<MidiPortManager> GetWeakPtrFromFactory() final {
510 DCHECK(thread_checker_.CalledOnValidThread());
511
512 return weak_factory_.GetWeakPtr();
513 }
514
515 // Last member to ensure destructed first.
516 base::WeakPtrFactory<MidiOutPortManager> weak_factory_;
517
518 DISALLOW_COPY_AND_ASSIGN(MidiOutPortManager);
519 };
520
521 MidiManagerWinrt::MidiManagerWinrt() : com_thread_("Windows MIDI COM Thread") {}
522
523 MidiManagerWinrt::~MidiManagerWinrt() {}
524
525 void MidiManagerWinrt::StartInitialization() {
526 DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN10);
527
528 com_thread_.init_com_with_mta(true);
529 com_thread_.Start();
530
531 com_thread_.task_runner()->PostTask(
532 FROM_HERE, base::Bind(&MidiManagerWinrt::InitializeOnComThread,
533 base::Unretained(this)));
534 }
535
536 void MidiManagerWinrt::Finalize() {
537 com_thread_.task_runner()->PostTask(
538 FROM_HERE, base::Bind(&MidiManagerWinrt::FinalizeOnComThread,
539 base::Unretained(this)));
540
541 // Blocks until FinalizeOnComThread() returns. Delayed MIDI send data tasks
542 // will be ignored.
543 com_thread_.Stop();
544
545 port_manager_ready_count_ = 0;
Takashi Toyoshima 2016/08/23 08:09:38 Probably, this isn't needed unless you have a spec
Shao-Chuan Lee 2016/08/24 08:50:31 Done. I was assuming that StartInitialization() an
546 }
547
548 void MidiManagerWinrt::DispatchSendMidiData(MidiManagerClient* client,
549 uint32_t port_index,
550 const std::vector<uint8_t>& data,
551 double timestamp) {
552 base::AutoLock auto_lock(scheduler_lock_);
553 if (!scheduler_)
554 return;
555
556 scheduler_->PostSendDataTask(
557 client, data.size(), timestamp,
558 base::Bind(&MidiManagerWinrt::SendOnComThread, base::Unretained(this),
559 port_index, data));
560 }
561
562 void MidiManagerWinrt::InitializeOnComThread() {
563 if (!com_thread_checker_)
Takashi Toyoshima 2016/08/23 08:09:37 Can we just simply assume InitializeOnComThread is
Shao-Chuan Lee 2016/08/24 08:50:31 Done, I think CHECK is not required here.
564 com_thread_checker_.reset(new base::ThreadChecker);
565 DCHECK(com_thread_checker_->CalledOnValidThread());
566
567 port_manager_in_.reset(new MidiInPortManager(this));
568 port_manager_out_.reset(new MidiOutPortManager(this));
569
570 {
571 base::AutoLock auto_lock(scheduler_lock_);
572 scheduler_.reset(new MidiScheduler(this));
573 }
574
575 port_manager_in_->StartWatcher();
576 port_manager_out_->StartWatcher();
577 }
578
579 void MidiManagerWinrt::FinalizeOnComThread() {
Takashi Toyoshima 2016/08/23 08:09:38 We need to have a lock to reflect pointer resets t
Shao-Chuan Lee 2016/08/24 08:50:31 Now using a single lock for all lazy-initialized m
580 DCHECK(com_thread_checker_->CalledOnValidThread());
581
582 {
583 base::AutoLock auto_lock(scheduler_lock_);
584 scheduler_.reset();
585 }
586
587 port_manager_in_.reset();
588 port_manager_out_.reset();
589 }
590
591 void MidiManagerWinrt::SendOnComThread(uint32_t port_index,
592 const std::vector<uint8_t>& data) {
593 DCHECK(com_thread_checker_->CalledOnValidThread());
594
595 WRL::ComPtr<IBuffer> buffer;
596 HRESULT hr =
597 GetBufferFactory()->Create(static_cast<UINT32>(data.size()), &buffer);
598 DCHECK(SUCCEEDED(hr));
599
600 hr = buffer->put_Length(static_cast<UINT32>(data.size()));
601 DCHECK(SUCCEEDED(hr));
602
603 uint8_t* p_buffer_data = GetPointerToBufferData(buffer.Get());
604
605 std::copy(data.begin(), data.end(), p_buffer_data);
606
607 MidiPort<IMidiOutPort>* port = port_manager_out_->GetPortByIndex(port_index);
608 DCHECK(port != nullptr);
609
610 hr = port->handle->SendBuffer(buffer.Get());
Takashi Toyoshima 2016/08/23 08:09:37 This is just a question because of my lack of C++/
611 DCHECK(SUCCEEDED(hr));
612 }
613
614 void MidiManagerWinrt::OnPortManagerReady() {
615 DCHECK(com_thread_checker_->CalledOnValidThread());
616 DCHECK(port_manager_ready_count_ < 2);
617
618 if (++port_manager_ready_count_ == 2)
619 CompleteInitialization(Result::OK);
620 }
621
622 MidiManager* MidiManager::Create() {
623 return new MidiManagerWinrt();
624 }
625
626 } // namespace midi
627 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698