Chromium Code Reviews| Index: media/midi/midi_manager_winrt.cc |
| diff --git a/media/midi/midi_manager_winrt.cc b/media/midi/midi_manager_winrt.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..016241b089bfc2d5a01ca4f497cf32d551d2f4ca |
| --- /dev/null |
| +++ b/media/midi/midi_manager_winrt.cc |
| @@ -0,0 +1,625 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "media/midi/midi_manager_winrt.h" |
| + |
| +#include <robuffer.h> |
| +#include <windows.devices.enumeration.h> |
| +#include <windows.devices.midi.h> |
| +#include <wrl/event.h> |
| + |
| +#include "base/bind.h" |
| +#include "base/containers/hash_tables.h" |
| +#include "base/strings/string16.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "base/timer/timer.h" |
| +#include "base/win/windows_version.h" |
| + |
| +namespace media { |
| +namespace midi { |
| +namespace { |
| + |
| +namespace WRL = Microsoft::WRL; |
| + |
| +using namespace ABI::Windows::Devices::Enumeration; |
| +using namespace ABI::Windows::Devices::Midi; |
| +using namespace ABI::Windows::Foundation; |
| +using namespace ABI::Windows::Storage::Streams; |
| + |
| +// Factory functions that activate and create WinRT components. The caller takes |
| +// ownership of the returning ComPtr. |
| +template <typename InterfaceType, base::char16 const* runtime_class_id> |
| +WRL::ComPtr<InterfaceType> WrlStaticsFactory() { |
| + WRL::ComPtr<InterfaceType> com_ptr; |
| + |
| + HRESULT hr = GetActivationFactory( |
| + WRL::Wrappers::HStringReference(runtime_class_id).Get(), &com_ptr); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + return com_ptr; |
| +} |
| + |
| +WRL::ComPtr<IBufferFactory> GetBufferFactory() { |
| + return WrlStaticsFactory<IBufferFactory, |
| + RuntimeClass_Windows_Storage_Streams_Buffer>(); |
| +} |
| + |
| +WRL::ComPtr<IDeviceInformationStatics> GetDeviceInformationStatics() { |
| + return WrlStaticsFactory< |
| + IDeviceInformationStatics, |
| + RuntimeClass_Windows_Devices_Enumeration_DeviceInformation>(); |
| +} |
| + |
| +template <typename T, HRESULT (T::*method)(HSTRING*)> |
| +std::string GetStringFromObjectMethod(T* obj) { |
| + HSTRING result; |
| + HRESULT hr = (obj->*method)(&result); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + const base::char16* buffer = WindowsGetStringRawBuffer(result, nullptr); |
| + if (buffer) |
| + return base::WideToUTF8(buffer); |
| + return std::string(); |
| +} |
| + |
| +template <typename T> |
| +std::string GetIdString(T* obj) { |
| + return GetStringFromObjectMethod<T, &T::get_Id>(obj); |
| +} |
| + |
| +template <typename T> |
| +std::string GetDeviceIdString(T* obj) { |
| + return GetStringFromObjectMethod<T, &T::get_DeviceId>(obj); |
| +} |
| + |
| +std::string GetNameString(IDeviceInformation* info) { |
| + return GetStringFromObjectMethod<IDeviceInformation, |
| + &IDeviceInformation::get_Name>(info); |
| +} |
| + |
| +uint8_t* GetPointerToBufferData(IBuffer* buffer) { |
| + WRL::ComPtr<IInspectable> inspectable( |
| + reinterpret_cast<IInspectable*>(buffer)); |
| + WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> buffer_byte_access; |
| + |
| + HRESULT hr = inspectable.As(&buffer_byte_access); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + uint8_t* ptr = nullptr; |
| + hr = buffer_byte_access->Buffer(&ptr); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + // Lifetime of the pointing buffer is controlled by the buffer object. |
| + return ptr; |
| +} |
| + |
| +template <typename InterfaceType> |
| +struct MidiPort { |
| + MidiPort() = default; |
| + |
| + uint32_t index; |
| + WRL::ComPtr<InterfaceType> handle; |
| + base::TimeTicks start_time; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(MidiPort); |
| +}; |
| + |
| +template <typename InterfaceType, |
| + typename RuntimeType, |
| + typename StaticsInterfaceType, |
| + base::char16 const* runtime_class_id> |
| +class MidiPortManager { |
| + public: |
| + // MidiPortManager instances should be constructed on the COM thread. |
| + MidiPortManager(MidiManagerWinrt* midi_manager) |
| + : midi_manager_(midi_manager), |
| + task_runner_(base::ThreadTaskRunnerHandle::Get()) {} |
| + |
| + void StartWatcher() { |
|
Shao-Chuan Lee
2016/08/23 04:33:29
Missing |thread_checker_| check.
|
| + HRESULT hr; |
| + |
| + midi_port_statics_ = |
| + WrlStaticsFactory<StaticsInterfaceType, runtime_class_id>(); |
| + |
| + HSTRING device_selector = nullptr; |
| + hr = midi_port_statics_->GetDeviceSelector(&device_selector); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + hr = GetDeviceInformationStatics()->CreateWatcherAqsFilter(device_selector, |
| + &watcher_); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + // Register callbacks to WinRT that post state-modifying jobs back to COM |
| + // thread. |weak_ptr| and |task_runner| are captured by lambda callbacks for |
| + // posting jobs. Note that WinRT callback arguments should not be passed |
| + // outside the callback since the pointers may be unavailable afterwards. |
| + base::WeakPtr<MidiPortManager> weak_ptr = GetWeakPtrFromFactory(); |
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_; |
| + |
| + hr = watcher_->add_Added( |
| + WRL::Callback<ITypedEventHandler<DeviceWatcher*, DeviceInformation*>>( |
| + [weak_ptr, task_runner](IDeviceWatcher* watcher, |
| + IDeviceInformation* info) { |
| + std::string dev_id = GetIdString(info), |
| + dev_name = GetNameString(info); |
| + |
| + task_runner->PostTask( |
| + FROM_HERE, base::Bind(&MidiPortManager::OnAdded, weak_ptr, |
| + dev_id, dev_name)); |
| + |
| + return S_OK; |
| + }) |
| + .Get(), |
| + &token_Added_); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + hr = watcher_->add_EnumerationCompleted( |
| + WRL::Callback<ITypedEventHandler<DeviceWatcher*, IInspectable*>>( |
| + [weak_ptr, task_runner](IDeviceWatcher* watcher, |
| + IInspectable* insp) { |
| + task_runner->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MidiPortManager::OnEnumerationCompleted, |
| + weak_ptr)); |
| + |
| + return S_OK; |
| + }) |
| + .Get(), |
| + &token_EnumerationCompleted_); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + hr = watcher_->add_Removed( |
| + WRL::Callback< |
| + ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>>( |
| + [weak_ptr, task_runner](IDeviceWatcher* watcher, |
| + IDeviceInformationUpdate* update) { |
| + std::string dev_id = GetIdString(update); |
| + |
| + task_runner->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MidiPortManager::OnRemoved, weak_ptr, dev_id)); |
| + |
| + return S_OK; |
| + }) |
| + .Get(), |
| + &token_Removed_); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + hr = watcher_->add_Stopped( |
| + WRL::Callback<ITypedEventHandler<DeviceWatcher*, IInspectable*>>( |
| + [](IDeviceWatcher* watcher, IInspectable* insp) { |
| + // Placeholder, does nothing for now. |
| + return S_OK; |
| + }) |
| + .Get(), |
| + &token_Stopped_); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + hr = watcher_->add_Updated( |
| + WRL::Callback< |
| + ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>>( |
| + [](IDeviceWatcher* watcher, IDeviceInformationUpdate* update) { |
| + // TODO(shaochuan): Check for fields to be updated here. |
| + return S_OK; |
| + }) |
| + .Get(), |
| + &token_Updated_); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + hr = watcher_->Start(); |
| + DCHECK(SUCCEEDED(hr)); |
| + } |
| + |
| + ~MidiPortManager() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + watcher_->remove_Added(token_Added_); |
| + watcher_->remove_EnumerationCompleted(token_EnumerationCompleted_); |
| + watcher_->remove_Removed(token_Removed_); |
| + watcher_->remove_Stopped(token_Stopped_); |
| + watcher_->remove_Updated(token_Updated_); |
| + |
| + watcher_->Stop(); |
| + } |
| + |
| + MidiPort<InterfaceType>* GetPortByDeviceId(std::string dev_id) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + auto it = ports_.find(dev_id); |
| + if (it == ports_.end()) |
| + return nullptr; |
| + return it->second.get(); |
| + } |
| + |
| + MidiPort<InterfaceType>* GetPortByIndex(uint32_t port_index) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + auto it = ports_.find(port_ids_[port_index]); |
| + if (it == ports_.end()) |
| + return nullptr; |
| + return it->second.get(); |
| + } |
| + |
| + protected: |
| + // The owning MidiManagerWinrt. |
| + MidiManagerWinrt* midi_manager_; |
| + |
| + // Task runner of the COM thread. |
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| + |
| + // Ensures all methods are called on the COM thread. |
| + base::ThreadChecker thread_checker_; |
| + |
| + private: |
| + // DeviceWatcher callbacks: |
| + void OnAdded(std::string dev_id, std::string dev_name) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + // TODO(shaochuan): Disable Microsoft GS Wavetable Synth due to security |
| + // reasons. http://crbug.com/499279 |
| + |
| + port_names_[dev_id] = dev_name; |
| + |
| + base::string16 dev_id_string16 = base::UTF8ToWide(dev_id); |
| + HSTRING dev_id_hstring; |
| + HRESULT hr = WindowsCreateString( |
| + dev_id_string16.c_str(), static_cast<UINT32>(dev_id_string16.length()), |
| + &dev_id_hstring); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + WRL::ComPtr<IAsyncOperation<RuntimeType*>> async_op; |
| + |
| + hr = midi_port_statics_->FromIdAsync(dev_id_hstring, &async_op); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + WindowsDeleteString(dev_id_hstring); |
| + dev_id_hstring = nullptr; |
| + |
| + base::WeakPtr<MidiPortManager> weak_ptr = GetWeakPtrFromFactory(); |
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_; |
| + |
| + hr = async_op->put_Completed( |
| + WRL::Callback<IAsyncOperationCompletedHandler<RuntimeType*>>( |
| + [weak_ptr, task_runner](IAsyncOperation<RuntimeType*>* async_op, |
| + AsyncStatus status) { |
| + // TODO(shaochuan): Check if port open time is accurate. |
| + const auto now = base::TimeTicks::Now(); |
| + |
| + InterfaceType* handle; |
| + HRESULT hr = async_op->GetResults(&handle); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + // |async_op| is owned by |async_ops_|, safe to pass outside. |
| + task_runner->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MidiPortManager::OnCompletedGetPortFromIdAsync, |
| + weak_ptr, handle, now, async_op)); |
| + |
| + return S_OK; |
| + }) |
| + .Get()); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + // Keep a reference to incompleted |async_op| to ensure lifetime. |
| + async_ops_.insert(std::move(async_op)); |
| + } |
| + |
| + void OnEnumerationCompleted() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + midi_manager_->OnPortManagerReady(); |
| + } |
| + |
| + void OnRemoved(std::string dev_id) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + MidiPort<InterfaceType>* port = GetPortByDeviceId(dev_id); |
| + DCHECK(port != nullptr); |
| + |
| + SetPortState(port->index, MIDI_PORT_DISCONNECTED); |
| + |
| + port->handle = nullptr; |
| + } |
| + |
| + void OnCompletedGetPortFromIdAsync(InterfaceType* handle, |
| + base::TimeTicks start_time, |
| + IAsyncOperation<RuntimeType*>* async_op) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + RegisterOnMessageReceived(handle); |
| + |
| + std::string dev_id = GetDeviceIdString(handle); |
| + |
| + MidiPort<InterfaceType>* port = GetPortByDeviceId(dev_id); |
| + |
| + if (port == nullptr) { |
| + // TODO(shaochuan): Fill in manufacturer and driver version. |
| + AddPort(MidiPortInfo(dev_id, std::string("Manufacturer"), |
| + port_names_[dev_id], std::string("DriverVersion"), |
| + MIDI_PORT_OPENED)); |
| + |
| + port = new MidiPort<InterfaceType>; |
| + port->index = static_cast<uint32_t>(port_ids_.size()); |
| + |
| + ports_[dev_id].reset(port); |
| + port_ids_.push_back(dev_id); |
| + } else { |
| + SetPortState(port->index, MIDI_PORT_CONNECTED); |
| + } |
| + |
| + port->handle = handle; |
| + port->start_time = start_time; |
| + |
| + // Remove reference to completed |async_op|. |
| + auto it = async_ops_.find(async_op); |
| + DCHECK(it != async_ops_.end()); |
| + async_ops_.erase(it); |
| + } |
| + |
| + // Overrided by MidiInPortManager to listen to input ports. |
| + virtual void RegisterOnMessageReceived(InterfaceType* handle) {} |
| + |
| + // Calls midi_manager_->Add{Input,Output}Port. |
| + virtual void AddPort(MidiPortInfo info) = 0; |
| + |
| + // Calls midi_manager_->Set{Input,Output}PortState. |
| + virtual void SetPortState(uint32_t port_index, MidiPortState state) = 0; |
| + |
| + // WeakPtrFactory has to be declared in derived class, use this method to |
| + // retrieve upcasted WeakPtr for posting tasks. |
| + virtual base::WeakPtr<MidiPortManager> GetWeakPtrFromFactory() = 0; |
| + |
| + // Midi{In,Out}PortStatics instance. |
| + WRL::ComPtr<StaticsInterfaceType> midi_port_statics_; |
| + |
| + // DeviceWatcher instance and event registration tokens for unsubscribing |
| + // events in destructor. |
| + WRL::ComPtr<IDeviceWatcher> watcher_; |
| + EventRegistrationToken token_Added_, token_EnumerationCompleted_, |
| + token_Removed_, token_Stopped_, token_Updated_; |
| + |
| + // All manipulations to these fields should be done on COM thread. |
| + base::hash_map<std::string, std::unique_ptr<MidiPort<InterfaceType>>> ports_; |
| + std::vector<std::string> port_ids_; |
| + base::hash_map<std::string, std::string> port_names_; |
| + |
| + // Keeps AsyncOperation objects before the operation completes. |
| + std::set<WRL::ComPtr<IAsyncOperation<RuntimeType*>>> async_ops_; |
| +}; |
| + |
| +} // namespace |
| + |
| +class MidiManagerWinrt::MidiInPortManager final |
| + : public MidiPortManager<IMidiInPort, |
| + MidiInPort, |
| + IMidiInPortStatics, |
| + RuntimeClass_Windows_Devices_Midi_MidiInPort> { |
| + public: |
| + MidiInPortManager(MidiManagerWinrt* midi_manager) |
| + : MidiPortManager(midi_manager), weak_factory_(this) {} |
| + |
| + private: |
| + // MidiPortManager overrides: |
| + void RegisterOnMessageReceived(IMidiInPort* handle) override { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + EventRegistrationToken& token = tokens_[GetDeviceIdString(handle)]; |
| + |
| + base::WeakPtr<MidiInPortManager> weak_ptr = weak_factory_.GetWeakPtr(); |
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_; |
| + |
| + handle->add_MessageReceived( |
| + WRL::Callback< |
| + ITypedEventHandler<MidiInPort*, MidiMessageReceivedEventArgs*>>( |
| + [weak_ptr, task_runner](IMidiInPort* handle, |
| + IMidiMessageReceivedEventArgs* args) { |
| + std::string dev_id = GetDeviceIdString(handle); |
| + |
| + WRL::ComPtr<IMidiMessage> message; |
| + HRESULT hr = args->get_Message(&message); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + WRL::ComPtr<IBuffer> buffer; |
| + hr = message->get_RawData(&buffer); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + uint8_t* p_buffer_data = GetPointerToBufferData(buffer.Get()); |
| + |
| + uint32_t data_length; |
| + hr = buffer->get_Length(&data_length); |
| + DCHECK(SUCCEEDED(hr)); |
| + DCHECK(data_length != 0); |
| + |
| + std::vector<uint8_t> data(p_buffer_data, |
| + p_buffer_data + data_length); |
| + |
| + // Time since port opened in 100-nanosecond units. |
| + TimeSpan time_span; |
| + hr = message->get_Timestamp(&time_span); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + task_runner->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MidiInPortManager::OnMessageReceived, weak_ptr, |
| + dev_id, data, base::TimeDelta::FromMicroseconds( |
| + time_span.Duration / 10))); |
| + |
| + return S_OK; |
| + }) |
| + .Get(), |
| + &token); |
| + } |
| + |
| + void AddPort(MidiPortInfo info) final { midi_manager_->AddInputPort(info); } |
| + |
| + void SetPortState(uint32_t port_index, MidiPortState state) final { |
| + midi_manager_->SetInputPortState(port_index, state); |
| + } |
| + |
| + base::WeakPtr<MidiPortManager> GetWeakPtrFromFactory() final { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + return weak_factory_.GetWeakPtr(); |
| + } |
| + |
| + // Callback on receiving MIDI input message. |
| + void OnMessageReceived(std::string dev_id, |
| + std::vector<uint8_t> data, |
| + base::TimeDelta time_since_start) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + MidiPort<IMidiInPort>* port = GetPortByDeviceId(dev_id); |
| + DCHECK(port != nullptr); |
| + |
| + midi_manager_->ReceiveMidiData(port->index, &data[0], data.size(), |
| + port->start_time + time_since_start); |
| + } |
| + |
| + // Event tokens for input message received events. |
| + base::hash_map<std::string, EventRegistrationToken> tokens_; |
| + |
| + // Last member to ensure destructed first. |
| + base::WeakPtrFactory<MidiInPortManager> weak_factory_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MidiInPortManager); |
| +}; |
| + |
| +class MidiManagerWinrt::MidiOutPortManager final |
| + : public MidiPortManager<IMidiOutPort, |
| + IMidiOutPort, |
| + IMidiOutPortStatics, |
| + RuntimeClass_Windows_Devices_Midi_MidiOutPort> { |
| + public: |
| + MidiOutPortManager(MidiManagerWinrt* midi_manager) |
| + : MidiPortManager(midi_manager), weak_factory_(this) {} |
| + |
| + private: |
| + // MidiPortManager overrides: |
| + void AddPort(MidiPortInfo info) final { midi_manager_->AddOutputPort(info); } |
| + |
| + void SetPortState(uint32_t port_index, MidiPortState state) final { |
| + midi_manager_->SetOutputPortState(port_index, state); |
| + } |
| + |
| + base::WeakPtr<MidiPortManager> GetWeakPtrFromFactory() final { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + return weak_factory_.GetWeakPtr(); |
| + } |
| + |
| + // Last member to ensure destructed first. |
| + base::WeakPtrFactory<MidiOutPortManager> weak_factory_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MidiOutPortManager); |
| +}; |
| + |
| +MidiManagerWinrt::MidiManagerWinrt() : com_thread_("Windows MIDI COM Thread") {} |
| + |
| +MidiManagerWinrt::~MidiManagerWinrt() {} |
| + |
| +void MidiManagerWinrt::StartInitialization() { |
| + DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN10); |
| + |
| + com_thread_.init_com_with_mta(true); |
| + com_thread_.Start(); |
| + |
| + com_thread_.task_runner()->PostTask( |
| + FROM_HERE, base::Bind(&MidiManagerWinrt::InitializeOnComThread, |
| + base::Unretained(this))); |
| +} |
| + |
| +void MidiManagerWinrt::Finalize() { |
| + com_thread_.task_runner()->PostTask( |
| + FROM_HERE, base::Bind(&MidiManagerWinrt::FinalizeOnComThread, |
| + base::Unretained(this))); |
| + |
| + // Blocks until FinalizeOnComThread() returns. Delayed MIDI send data tasks |
| + // will be ignored. |
| + com_thread_.Stop(); |
| + |
| + port_manager_ready_count_ = 0; |
| +} |
| + |
| +void MidiManagerWinrt::DispatchSendMidiData(MidiManagerClient* client, |
| + uint32_t port_index, |
| + const std::vector<uint8_t>& data, |
| + double timestamp) { |
| + base::AutoLock auto_lock(scheduler_lock_); |
| + if (!scheduler_) |
| + return; |
| + |
| + scheduler_->PostSendDataTask( |
| + client, data.size(), timestamp, |
| + base::Bind(&MidiManagerWinrt::SendOnComThread, base::Unretained(this), |
| + port_index, data), |
| + com_thread_.task_runner()); |
| +} |
| + |
| +void MidiManagerWinrt::InitializeOnComThread() { |
| + if (!com_thread_checker_) |
| + com_thread_checker_.reset(new base::ThreadChecker); |
| + DCHECK(com_thread_checker_->CalledOnValidThread()); |
| + |
| + port_manager_in_.reset(new MidiInPortManager(this)); |
| + port_manager_out_.reset(new MidiOutPortManager(this)); |
| + |
| + { |
| + base::AutoLock auto_lock(scheduler_lock_); |
| + scheduler_.reset(new MidiScheduler(this)); |
| + } |
| + |
| + port_manager_in_->StartWatcher(); |
| + port_manager_out_->StartWatcher(); |
| +} |
| + |
| +void MidiManagerWinrt::FinalizeOnComThread() { |
| + DCHECK(com_thread_checker_->CalledOnValidThread()); |
| + |
| + { |
| + base::AutoLock auto_lock(scheduler_lock_); |
| + scheduler_.reset(); |
| + } |
| + |
| + port_manager_in_.reset(); |
| + port_manager_out_.reset(); |
| +} |
| + |
| +void MidiManagerWinrt::SendOnComThread(uint32_t port_index, |
| + const std::vector<uint8_t>& data) { |
| + DCHECK(com_thread_checker_->CalledOnValidThread()); |
| + |
| + WRL::ComPtr<IBuffer> buffer; |
| + HRESULT hr = |
| + GetBufferFactory()->Create(static_cast<UINT32>(data.size()), &buffer); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + hr = buffer->put_Length(static_cast<UINT32>(data.size())); |
| + DCHECK(SUCCEEDED(hr)); |
| + |
| + uint8_t* p_buffer_data = GetPointerToBufferData(buffer.Get()); |
| + |
| + std::copy(data.begin(), data.end(), p_buffer_data); |
| + |
| + MidiPort<IMidiOutPort>* port = port_manager_out_->GetPortByIndex(port_index); |
| + DCHECK(port != nullptr); |
| + |
| + hr = port->handle->SendBuffer(buffer.Get()); |
| + DCHECK(SUCCEEDED(hr)); |
| +} |
| + |
| +void MidiManagerWinrt::OnPortManagerReady() { |
| + DCHECK(com_thread_checker_->CalledOnValidThread()); |
| + DCHECK(port_manager_ready_count_ < 2); |
| + |
| + if (++port_manager_ready_count_ == 2) |
| + CompleteInitialization(Result::OK); |
| +} |
| + |
| +MidiManager* MidiManager::Create() { |
| + return new MidiManagerWinrt(); |
| +} |
| + |
| +} // namespace midi |
| +} // namespace media |