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..d81fb49877d481d6eb0fb0b7a06a388892c0f4d6 |
| --- /dev/null |
| +++ b/media/midi/midi_manager_winrt.cc |
| @@ -0,0 +1,661 @@ |
| +// 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_win.h" |
| + |
| +#include <robuffer.h> |
| +#include <windows.devices.enumeration.h> |
| +#include <windows.devices.midi.h> |
| +#include <wrl/event.h> |
| + |
| +#include <functional> |
| + |
| +#include "base/bind.h" |
| +#include "base/containers/hash_tables.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "base/timer/timer.h" |
| +#include "base/win/windows_version.h" |
| +#include "media/midi/midi_port_info.h" |
| + |
| +namespace media { |
| +namespace midi { |
| +namespace { |
| + |
| +using namespace ABI::Windows::Devices::Enumeration; |
| +using namespace ABI::Windows::Devices::Midi; |
| +using namespace ABI::Windows::Foundation; |
| +using namespace ABI::Windows::Storage::Streams; |
| +using Microsoft::WRL::Callback; |
|
Takashi Toyoshima
2016/08/15 08:46:23
To shorten this as Callback is a little confusing
Shao-Chuan Lee
2016/08/16 07:42:25
Now using `namespace WRL = Microsoft::WRL`.
|
| +using Microsoft::WRL::ComPtr; |
| +using Microsoft::WRL::Wrappers::HStringReference; |
| + |
| +using std::placeholders::_1; |
| +using std::placeholders::_2; |
| + |
| +// Singleton helper for accessing WRL static methods. |
| +class WrlStatics { |
|
Takashi Toyoshima
2016/08/15 08:46:23
Please use base::LazyInstance to implement a singl
Shao-Chuan Lee
2016/08/16 07:42:24
The singleton is now replaced with functions. Alth
|
| + public: |
| + static WrlStatics& GetInstance() { |
| + static WrlStatics instance; |
| + return instance; |
| + } |
| + |
| + auto GetBufferFactory() { |
| + return GetStatics(buffer_factory_, |
| + RuntimeClass_Windows_Storage_Streams_Buffer); |
| + } |
| + |
| + auto GetDeviceInformationStatics() { |
| + return GetStatics( |
| + device_information_statics_, |
| + RuntimeClass_Windows_Devices_Enumeration_DeviceInformation); |
| + } |
| + |
| + auto GetMidiInPortStatics() { |
| + return GetStatics(midi_in_port_statics_, |
| + RuntimeClass_Windows_Devices_Midi_MidiInPort); |
| + } |
| + |
| + auto GetMidiOutPortStatics() { |
| + return GetStatics(midi_out_port_statics_, |
| + RuntimeClass_Windows_Devices_Midi_MidiOutPort); |
| + } |
| + |
| + private: |
| + WrlStatics() {} |
| + |
| + template <typename T> |
| + static T* GetStatics(ComPtr<T>& com_ptr, wchar_t const* class_id) { |
|
Takashi Toyoshima
2016/08/15 08:46:23
Also wchar_t is disallowed in chromium even though
Takashi Toyoshima
2016/08/15 08:46:23
chromium style suggests to use pointers* or const
Shao-Chuan Lee
2016/08/16 07:42:25
Done.
Shao-Chuan Lee
2016/08/16 07:42:25
Done.
|
| + if (com_ptr == nullptr) { |
| + HRESULT hr = |
| + GetActivationFactory(HStringReference(class_id).Get(), &com_ptr); |
| + DCHECK(!FAILED(hr)); |
| + } |
| + return com_ptr.Get(); |
| + } |
| + |
| + ComPtr<IBufferFactory> buffer_factory_; |
| + ComPtr<IDeviceInformationStatics> device_information_statics_; |
| + ComPtr<IMidiInPortStatics> midi_in_port_statics_; |
| + ComPtr<IMidiOutPortStatics> midi_out_port_statics_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(WrlStatics); |
| +}; |
| + |
| +// Helper for setting up DeviceWatcher callbacks. |
| +class DeviceWatcherWrapper { |
|
Takashi Toyoshima
2016/08/15 08:46:24
This looks over-abstracted to me.
The midi_manager
Shao-Chuan Lee
2016/08/16 07:42:25
Merged into MidiPortManager.
|
| + public: |
| + class CallbackHandler { |
| + public: |
| + virtual HRESULT OnAdded(IDeviceWatcher* watcher, |
| + IDeviceInformation* info) = 0; |
| + virtual HRESULT OnEnumerationCompleted(IDeviceWatcher* watcher, |
| + IInspectable* insp) = 0; |
| + virtual HRESULT OnRemoved(IDeviceWatcher* watcher, |
| + IDeviceInformationUpdate* update) = 0; |
| + virtual HRESULT OnStopped(IDeviceWatcher* watcher, IInspectable* insp) = 0; |
| + virtual HRESULT OnUpdated(IDeviceWatcher* watcher, |
| + IDeviceInformationUpdate* update) = 0; |
| + }; |
| + |
| + DeviceWatcherWrapper() {} |
| + |
| + ~DeviceWatcherWrapper() { |
| + 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_); |
| + } |
| + |
| + void Setup(HSTRING selector, CallbackHandler* handler) { |
| + HRESULT hr; |
| + |
| + hr = WrlStatics::GetInstance() |
| + .GetDeviceInformationStatics() |
| + ->CreateWatcherAqsFilter(selector, &watcher_); |
| + DCHECK(!FAILED(hr)); |
| + |
| + hr = watcher_->add_Added( |
| + Callback<ITypedEventHandler<DeviceWatcher*, DeviceInformation*>>( |
| + std::bind(&CallbackHandler::OnAdded, handler, _1, _2)) |
|
Takashi Toyoshima
2016/08/15 08:46:23
std::bind is classified to a C++11 features to be
Shao-Chuan Lee
2016/08/16 07:42:25
Acknowledged, will look for advice on this issue (
Shao-Chuan Lee
2016/08/16 09:24:34
Just realized that WRL::Callback supports calling
|
| + .Get(), |
| + &token_Added_); |
| + DCHECK(!FAILED(hr)); |
| + |
| + hr = watcher_->add_EnumerationCompleted( |
| + Callback<ITypedEventHandler<DeviceWatcher*, IInspectable*>>( |
| + std::bind(&CallbackHandler::OnEnumerationCompleted, handler, _1, |
| + _2)) |
| + .Get(), |
| + &token_EnumerationCompleted_); |
| + DCHECK(!FAILED(hr)); |
| + |
| + hr = watcher_->add_Removed( |
| + Callback<ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>>( |
| + std::bind(&CallbackHandler::OnRemoved, handler, _1, _2)) |
| + .Get(), |
| + &token_Removed_); |
| + DCHECK(!FAILED(hr)); |
| + |
| + hr = watcher_->add_Stopped( |
| + Callback<ITypedEventHandler<DeviceWatcher*, IInspectable*>>( |
| + std::bind(&CallbackHandler::OnStopped, handler, _1, _2)) |
| + .Get(), |
| + &token_Stopped_); |
| + DCHECK(!FAILED(hr)); |
| + |
| + hr = watcher_->add_Updated( |
| + Callback<ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>>( |
| + std::bind(&CallbackHandler::OnUpdated, handler, _1, _2)) |
| + .Get(), |
| + &token_Updated_); |
| + DCHECK(!FAILED(hr)); |
| + |
| + hr = watcher_->Start(); |
| + DCHECK(!FAILED(hr)); |
| + } |
| + |
| + private: |
| + ComPtr<IDeviceWatcher> watcher_; |
| + EventRegistrationToken token_Added_, token_EnumerationCompleted_, |
| + token_Removed_, token_Stopped_, token_Updated_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(DeviceWatcherWrapper); |
| +}; |
| + |
| +template <typename T> |
| +inline std::string GetIdString(T obj) { |
| + HSTRING hs; |
| + HRESULT hr = obj->get_Id(&hs); |
| + DCHECK(!FAILED(hr)); |
| + return base::WideToUTF8(WindowsGetStringRawBuffer(hs, nullptr)); |
| +} |
| + |
| +template <typename T> |
| +inline std::string GetDeviceIdString(T obj) { |
| + HSTRING hs; |
| + HRESULT hr = obj->get_DeviceId(&hs); |
| + DCHECK(!FAILED(hr)); |
| + return base::WideToUTF8(WindowsGetStringRawBuffer(hs, nullptr)); |
| +} |
| + |
| +inline std::string GetNameString(IDeviceInformation* info) { |
| + HSTRING hs; |
| + HRESULT hr = info->get_Name(&hs); |
| + DCHECK(!FAILED(hr)); |
| + return base::WideToUTF8(WindowsGetStringRawBuffer(hs, nullptr)); |
| +} |
| + |
| +template <typename InterfaceType> |
| +struct MidiPort { |
| + MidiPort() {} |
| + |
| + uint32_t index; |
| + ComPtr<InterfaceType> handle; |
| + base::TimeTicks start_time; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(MidiPort); |
| +}; |
| + |
| +template <typename InterfaceType, typename RuntimeType> |
| +class MidiPortManager : public DeviceWatcherWrapper::CallbackHandler { |
| + public: |
| + void SetDelegate(MidiServiceWinDelegate* delegate) { delegate_ = delegate; } |
| + |
| + MidiPort<InterfaceType>* GetPortByDeviceId(std::string dev_id) { |
| + base::AutoLock auto_lock(ports_lock_); |
| + auto it = ports_.find(dev_id); |
| + if (it == ports_.end()) |
| + return nullptr; |
| + return it->second.get(); |
| + } |
| + |
| + MidiPort<InterfaceType>* GetPortByIndex(uint32_t port_index) { |
| + base::AutoLock auto_lock(ports_lock_); |
| + auto it = ports_.find(port_ids_[port_index]); |
| + if (it == ports_.end()) |
| + return nullptr; |
| + return it->second.get(); |
| + } |
| + |
| + // DeviceWatcherWrapper::CallbackHandler overrides: |
| + HRESULT OnAdded(IDeviceWatcher* watcher, IDeviceInformation* info) override { |
| + HSTRING dev_id_hs; |
| + HRESULT hr = info->get_Id(&dev_id_hs); |
| + DCHECK(!FAILED(hr)); |
| + |
| + std::string dev_id = |
| + base::WideToUTF8(WindowsGetStringRawBuffer(dev_id_hs, nullptr)); |
| + |
| + { |
| + base::AutoLock auto_lock(ports_lock_); |
| + port_names_[dev_id] = GetNameString(info); |
| + } |
| + |
| + ComPtr<IAsyncOperation<RuntimeType*>> async_op; |
| + |
| + RegisterGetPortFromIdAsync(&async_op, dev_id_hs); |
| + |
| + hr = async_op->put_Completed( |
| + Callback<IAsyncOperationCompletedHandler<RuntimeType*>>( |
| + std::bind(&MidiPortManager::OnCompletedGetPortFromIdAsync, this, _1, |
| + _2)) |
| + .Get()); |
| + DCHECK(!FAILED(hr)); |
| + |
| + { |
| + base::AutoLock auto_lock(async_ops_lock_); |
| + async_ops_.insert(std::move(async_op)); |
| + } |
| + |
| + return S_OK; |
| + } |
| + |
| + HRESULT OnEnumerationCompleted(IDeviceWatcher* watcher, |
| + IInspectable* insp) override { |
| + // TODO(shaochuan) |
| + return S_OK; |
| + } |
| + |
| + HRESULT OnRemoved(IDeviceWatcher* watcher, |
| + IDeviceInformationUpdate* update) override { |
| + MidiPort<InterfaceType>* port = GetPortByDeviceId(GetIdString(update)); |
| + DCHECK(port != nullptr); |
| + |
| + SetPortState(port->index, MIDI_PORT_DISCONNECTED); |
| + |
| + port->handle = nullptr; |
| + |
| + return S_OK; |
| + } |
| + |
| + HRESULT OnStopped(IDeviceWatcher* watcher, IInspectable* insp) override { |
| + // TODO(shaochuan) |
| + return S_OK; |
| + } |
| + |
| + HRESULT OnUpdated(IDeviceWatcher* watcher, |
| + IDeviceInformationUpdate* update) override { |
| + // TODO(shaochuan) |
| + return S_OK; |
| + } |
| + |
| + protected: |
| + MidiServiceWinDelegate* delegate_; |
| + |
| + private: |
| + HRESULT OnCompletedGetPortFromIdAsync(IAsyncOperation<RuntimeType*>* async_op, |
| + AsyncStatus status) { |
| + const auto now = base::TimeTicks::Now(); |
| + |
| + InterfaceType* handle; |
| + HRESULT hr = async_op->GetResults(&handle); |
| + DCHECK(!FAILED(hr)); |
| + |
| + RegisterOnMessageReceived(handle); |
| + |
| + std::string dev_id = GetDeviceIdString(handle); |
| + |
| + MidiPort<InterfaceType>* port = GetPortByDeviceId(dev_id); |
| + |
| + if (port == nullptr) { |
| + base::AutoLock auto_lock(ports_lock_); |
| + |
| + // TODO(shaochuan) |
| + 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 = now; |
| + |
| + { |
| + base::AutoLock auto_lock(async_ops_lock_); |
| + auto it = async_ops_.find(async_op); |
| + DCHECK(it != async_ops_.end()); |
| + async_ops_.erase(it); |
| + } |
| + |
| + return S_OK; |
| + } |
| + |
| + // Implemented by child classes to call corresponding input/output methods. |
| + virtual void RegisterGetPortFromIdAsync( |
| + IAsyncOperation<RuntimeType*>** p_async_op, |
| + HSTRING dev_id) = 0; |
| + |
| + virtual void RegisterOnMessageReceived(InterfaceType* handle) = 0; |
| + |
| + virtual void AddPort(MidiPortInfo info) = 0; |
| + |
| + virtual void SetPortState(uint32_t port_index, MidiPortState state) = 0; |
| + |
| + base::Lock ports_lock_; |
| + base::hash_map<std::string, std::unique_ptr<MidiPort<InterfaceType>>> |
| + ports_; // GUARDED_BY(ports_lock_) |
| + std::vector<std::string> port_ids_; // GUARDED_BY(ports_lock_) |
| + base::hash_map<std::string, std::string> |
| + port_names_; // GUARDED_BY(ports_lock_) |
| + |
| + base::Lock async_ops_lock_; |
| + std::set<ComPtr<IAsyncOperation<RuntimeType*>>> |
| + async_ops_; // GUARDED_BY(async_ops_lock_) |
| +}; |
| + |
| +class MidiInPortManager final |
| + : public MidiPortManager<IMidiInPort, MidiInPort> { |
| + public: |
| + MidiInPortManager() {} |
| + |
| + private: |
| + // MidiPortManager overrides: |
| + void RegisterGetPortFromIdAsync(IAsyncOperation<MidiInPort*>** p_async_op, |
| + HSTRING dev_id) override { |
| + HRESULT hr = WrlStatics::GetInstance().GetMidiInPortStatics()->FromIdAsync( |
| + dev_id, p_async_op); |
| + DCHECK(!FAILED(hr)); |
| + } |
| + |
| + void RegisterOnMessageReceived(IMidiInPort* handle) override { |
| + base::AutoLock auto_lock(tokens_lock_); |
| + EventRegistrationToken& token = tokens_[GetDeviceIdString(handle)]; |
| + |
| + handle->add_MessageReceived( |
| + Callback< |
| + ITypedEventHandler<MidiInPort*, MidiMessageReceivedEventArgs*>>( |
| + std::bind(&MidiInPortManager::OnMessageReceived, this, _1, _2)) |
| + .Get(), |
| + &token); |
| + } |
| + |
| + void AddPort(MidiPortInfo info) { delegate_->OnAddInputPort(info); } |
| + |
| + void SetPortState(uint32_t port_index, MidiPortState state) { |
| + delegate_->OnSetInputPortState(port_index, state); |
| + } |
| + |
| + // Callback on receiving MIDI input message. |
| + HRESULT OnMessageReceived(IMidiInPort* handle, |
| + IMidiMessageReceivedEventArgs* args) { |
| + MidiPort<IMidiInPort>* port = GetPortByDeviceId(GetDeviceIdString(handle)); |
| + DCHECK(port != nullptr); |
| + |
| + ComPtr<IMidiMessage> message; |
| + HRESULT hr = args->get_Message(&message); |
| + DCHECK(!FAILED(hr)); |
| + |
| + ComPtr<IBuffer> buffer; |
| + hr = message->get_RawData(&buffer); |
| + DCHECK(!FAILED(hr)); |
| + |
| + // Use BufferByteAccess object to access buffer memory directly. |
| + ComPtr<IInspectable> insp(reinterpret_cast<IInspectable*>(buffer.Get())); |
| + ComPtr<Windows::Storage::Streams::IBufferByteAccess> bba; |
| + hr = insp.As(&bba); |
| + DCHECK(!FAILED(hr)); |
| + |
| + uint8_t* data_arr = nullptr; |
| + hr = bba->Buffer(reinterpret_cast<byte**>(&data_arr)); |
| + DCHECK(!FAILED(hr)); |
| + |
| + uint32_t len; |
| + hr = buffer->get_Length(&len); |
| + DCHECK(!FAILED(hr)); |
| + DCHECK(len != 0); |
| + |
| + std::vector<uint8_t> data(data_arr, data_arr + len); |
| + |
| + // Time since port opened in 100-nanosecond units. |
| + TimeSpan time_span; |
| + hr = message->get_Timestamp(&time_span); |
| + DCHECK(!FAILED(hr)); |
| + |
| + delegate_->OnReceiveMidiData( |
| + port->index, data, port->start_time + base::TimeDelta::FromMicroseconds( |
| + time_span.Duration / 10)); |
| + |
| + return S_OK; |
| + } |
| + |
| + base::Lock tokens_lock_; |
| + base::hash_map<std::string, EventRegistrationToken> |
| + tokens_; // GUARDED_BY(tokens_lock_) |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MidiInPortManager); |
| +}; |
| + |
| +class MidiOutPortManager final |
| + : public MidiPortManager<IMidiOutPort, IMidiOutPort> { |
| + public: |
| + MidiOutPortManager() {} |
| + |
| + private: |
| + // MidiPortManager overrides: |
| + void RegisterGetPortFromIdAsync(IAsyncOperation<IMidiOutPort*>** p_async_op, |
| + HSTRING dev_id) override { |
| + HRESULT hr = WrlStatics::GetInstance().GetMidiOutPortStatics()->FromIdAsync( |
| + dev_id, p_async_op); |
| + DCHECK(!FAILED(hr)); |
| + } |
| + |
| + void RegisterOnMessageReceived(IMidiOutPort* handle) override {} |
| + |
| + void AddPort(MidiPortInfo info) { delegate_->OnAddOutputPort(info); } |
| + |
| + void SetPortState(uint32_t port_index, MidiPortState state) { |
| + delegate_->OnSetOutputPortState(port_index, state); |
| + } |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MidiOutPortManager); |
| +}; |
| + |
| +HSTRING GetMidiInPortSelector() { |
| + HSTRING selector = nullptr; |
| + HRESULT hr = |
| + WrlStatics::GetInstance().GetMidiInPortStatics()->GetDeviceSelector( |
| + &selector); |
| + DCHECK(!FAILED(hr)); |
| + return selector; |
| +} |
| + |
| +HSTRING GetMidiOutPortSelector() { |
| + HSTRING selector = nullptr; |
| + HRESULT hr = |
| + WrlStatics::GetInstance().GetMidiOutPortStatics()->GetDeviceSelector( |
| + &selector); |
| + DCHECK(!FAILED(hr)); |
| + return selector; |
| +} |
| + |
| +class MidiServiceWinrtImpl : public MidiServiceWin { |
|
Takashi Toyoshima
2016/08/15 08:46:24
Can you remove MidiService* layers and implement d
Shao-Chuan Lee
2016/08/16 07:42:24
Done.
|
| + public: |
| + MidiServiceWinrtImpl() |
| + : delegate_(nullptr), |
| + com_thread_("Windows MIDI COM thread"), |
| + manager_in_(), |
| + manager_out_(), |
| + watcher_in_(), |
| + watcher_out_() {} |
| + |
| + ~MidiServiceWinrtImpl() final { com_thread_.Stop(); } |
| + |
| + // MidiServiceWin overrides: |
| + void InitializeAsync(MidiServiceWinDelegate* delegate) final { |
| + delegate_ = delegate; |
| + |
| + com_thread_.init_com_with_mta(true); |
| + com_thread_.Start(); |
| + |
| + manager_in_.SetDelegate(delegate); |
| + manager_out_.SetDelegate(delegate); |
| + |
| + com_thread_.message_loop()->PostTask( |
| + FROM_HERE, base::Bind(&MidiServiceWinrtImpl::InitializeOnComThread, |
| + base::Unretained(this))); |
| + |
| + delegate_->OnCompleteInitialization(Result::OK); |
| + } |
| + |
| + void SendMidiDataAsync(uint32_t port_index, |
| + const std::vector<uint8_t>& data, |
| + base::TimeTicks time) final { |
| + const auto now = base::TimeTicks::Now(); |
| + if (now < time) { |
| + com_thread_.message_loop()->PostDelayedTask( |
| + FROM_HERE, base::Bind(&MidiServiceWinrtImpl::SendOnComThread, |
| + base::Unretained(this), port_index, data, time), |
| + time - now); |
| + } else { |
| + com_thread_.message_loop()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MidiServiceWinrtImpl::SendOnComThread, |
| + base::Unretained(this), port_index, data, time)); |
| + } |
| + } |
| + |
| + private: |
| + ///////////////////////////////////////////////////////////////////////////// |
| + // Callbacks on the COM thread. |
| + ///////////////////////////////////////////////////////////////////////////// |
| + |
| + void AssertOnComThread() { |
| + DCHECK_EQ(com_thread_.GetThreadId(), base::PlatformThread::CurrentId()); |
| + } |
| + |
| + void InitializeOnComThread() { |
| + AssertOnComThread(); |
| + |
| + watcher_in_.Setup(GetMidiInPortSelector(), &manager_in_); |
| + watcher_out_.Setup(GetMidiOutPortSelector(), &manager_out_); |
| + } |
| + |
| + void SendOnComThread(uint32_t port_index, |
| + const std::vector<uint8_t>& data, |
| + base::TimeTicks time) { |
| + AssertOnComThread(); |
| + |
| + ComPtr<IBuffer> buffer; |
| + HRESULT hr = WrlStatics::GetInstance().GetBufferFactory()->Create( |
| + static_cast<UINT32>(data.size()), &buffer); |
| + DCHECK(!FAILED(hr)); |
| + |
| + hr = buffer->put_Length(static_cast<UINT32>(data.size())); |
| + DCHECK(!FAILED(hr)); |
| + |
| + // Use BufferByteAccess object to access buffer memory directly. |
| + ComPtr<IInspectable> insp(reinterpret_cast<IInspectable*>(buffer.Get())); |
| + ComPtr<Windows::Storage::Streams::IBufferByteAccess> bba; |
| + hr = insp.As(&bba); |
| + DCHECK(!FAILED(hr)); |
| + |
| + uint8_t* data_arr = nullptr; |
| + hr = bba->Buffer(reinterpret_cast<byte**>(&data_arr)); |
| + DCHECK(!FAILED(hr)); |
| + |
| + std::copy(data.begin(), data.end(), data_arr); |
| + |
| + MidiPort<IMidiOutPort>* port = manager_out_.GetPortByIndex(port_index); |
| + DCHECK(port != nullptr); |
| + |
| + hr = port->handle->SendBuffer(buffer.Get()); |
| + DCHECK(!FAILED(hr)); |
| + } |
| + |
| + ///////////////////////////////////////////////////////////////////////////// |
| + // Fields: |
| + ///////////////////////////////////////////////////////////////////////////// |
| + |
| + // Does not take ownership. |
| + MidiServiceWinDelegate* delegate_; |
| + |
| + base::Thread com_thread_; |
| + |
| + MidiInPortManager manager_in_; |
| + MidiOutPortManager manager_out_; |
| + DeviceWatcherWrapper watcher_in_, watcher_out_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MidiServiceWinrtImpl); |
| +}; |
| + |
| +} // namespace |
| + |
| +MidiManagerWin::MidiManagerWin() {} |
| + |
| +MidiManagerWin::~MidiManagerWin() {} |
| + |
| +void MidiManagerWin::StartInitialization() { |
| + DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN10); |
|
Takashi Toyoshima
2016/08/15 08:46:23
Is this check enough?
I mean is 10.0.10240.0 the f
Shao-Chuan Lee
2016/08/16 07:42:25
10.0.10240.0 seems to be the first release of Wind
|
| + midi_service_.reset(new MidiServiceWinrtImpl); |
| + midi_service_->InitializeAsync(this); |
| +} |
| + |
| +void MidiManagerWin::Finalize() { |
| + midi_service_.reset(); |
| +} |
| + |
| +void MidiManagerWin::DispatchSendMidiData(MidiManagerClient* client, |
| + uint32_t port_index, |
| + const std::vector<uint8_t>& data, |
| + double timestamp) { |
| + if (!midi_service_) |
| + return; |
| + |
| + base::TimeTicks time_to_send = base::TimeTicks::Now(); |
| + if (timestamp != 0.0) { |
| + time_to_send = |
| + base::TimeTicks() + base::TimeDelta::FromMicroseconds( |
| + timestamp * base::Time::kMicrosecondsPerSecond); |
| + } |
| + midi_service_->SendMidiDataAsync(port_index, data, time_to_send); |
|
Takashi Toyoshima
2016/08/15 08:46:24
Can you use MidiScheduler here? It would also make
Shao-Chuan Lee
2016/08/16 07:42:24
Using MidiScheduler now, but an extra wrapper is r
|
| + |
| + // TOOD(toyoshim): This calculation should be done when the date is actually |
| + // sent. |
| + client->AccumulateMidiBytesSent(data.size()); |
| +} |
| + |
| +void MidiManagerWin::OnCompleteInitialization(Result result) { |
| + CompleteInitialization(result); |
| +} |
| + |
| +void MidiManagerWin::OnAddInputPort(MidiPortInfo info) { |
| + AddInputPort(info); |
| +} |
| + |
| +void MidiManagerWin::OnAddOutputPort(MidiPortInfo info) { |
| + AddOutputPort(info); |
| +} |
| + |
| +void MidiManagerWin::OnSetInputPortState(uint32_t port_index, |
| + MidiPortState state) { |
| + SetInputPortState(port_index, state); |
| +} |
| + |
| +void MidiManagerWin::OnSetOutputPortState(uint32_t port_index, |
| + MidiPortState state) { |
| + SetOutputPortState(port_index, state); |
| +} |
| + |
| +void MidiManagerWin::OnReceiveMidiData(uint32_t port_index, |
| + const std::vector<uint8_t>& data, |
| + base::TimeTicks time) { |
| + ReceiveMidiData(port_index, &data[0], data.size(), time); |
| +} |
| + |
| +MidiManager* MidiManager::Create() { |
| + return new MidiManagerWin(); |
| +} |
| + |
| +} // namespace midi |
| +} // namespace media |