Chromium Code Reviews| Index: media/midi/dynamically_initialized_midi_manager_win.cc |
| diff --git a/media/midi/dynamically_initialized_midi_manager_win.cc b/media/midi/dynamically_initialized_midi_manager_win.cc |
| index 26a4c835e181e62691f21b8853a0c7fa84fa9c44..94262300900c9f82a95eeb2ca6e1f9b2a39040c2 100644 |
| --- a/media/midi/dynamically_initialized_midi_manager_win.cc |
| +++ b/media/midi/dynamically_initialized_midi_manager_win.cc |
| @@ -19,6 +19,8 @@ |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/synchronization/lock.h" |
| +#include "base/time/time.h" |
| +#include "media/midi/message_util.h" |
| #include "media/midi/midi_port_info.h" |
| #include "media/midi/midi_service.h" |
| @@ -26,6 +28,10 @@ namespace midi { |
| namespace { |
| +// Assumes that nullptr represents an invalid MIDI handle. |
| +constexpr HMIDIIN kInvalidInHandle = nullptr; |
| +constexpr HMIDIOUT kInvalidOutHandle = nullptr; |
| + |
| // Global variables to identify MidiManager instance. |
| constexpr int kInvalidInstanceId = -1; |
| int g_active_instance_id = kInvalidInstanceId; |
| @@ -69,6 +75,33 @@ void RunTask(int instance_id, const base::Closure& task) { |
| // TODO(toyoshim): Factor out TaskRunner related functionaliries above, and |
| // deprecate MidiScheduler. It should be available via MidiManager::scheduler(). |
| +// Helper functions to close MIDI device handles on TaskRunner asynchronously. |
| +void FinalizeInPort(HMIDIIN handle) { |
| + midiInClose(handle); |
| +} |
| + |
| +void FinalizeOutPort(HMIDIOUT handle) { |
| + midiOutClose(handle); |
| +} |
| + |
| +// Handles MIDI input port callbacks that runs on a system provided thread. |
| +void CALLBACK HandleMidiInCallback(HMIDIIN hmi, |
| + UINT msg, |
| + DWORD_PTR instance, |
| + DWORD_PTR param1, |
| + DWORD_PTR param2) { |
| + // TODO(toyoshim): Following patches will implement actual functions. |
| +} |
| + |
| +// Handles MIDI output port callbacks that runs on a system provided thread. |
| +void CALLBACK HandleMidiOutCallback(HMIDIOUT hmo, |
| + UINT msg, |
| + DWORD_PTR instance, |
| + DWORD_PTR param1, |
| + DWORD_PTR param2) { |
| + // TODO(toyoshim): Following patches will implement actual functions. |
| +} |
| + |
| class Port { |
| public: |
| Port(const std::string& type, |
| @@ -155,16 +188,19 @@ class Port { |
| // TODO(toyoshim): Following patches will implement actual functions. |
| class DynamicallyInitializedMidiManagerWin::InPort final : public Port { |
| public: |
| - InPort(UINT device_id, const MIDIINCAPS2W& caps) |
| + InPort(int instance_id, UINT device_id, const MIDIINCAPS2W& caps) |
| : Port("input", |
| device_id, |
| caps.wMid, |
| caps.wPid, |
| caps.vDriverVersion, |
| base::WideToUTF8( |
| - base::string16(caps.szPname, wcslen(caps.szPname)))) {} |
| + base::string16(caps.szPname, wcslen(caps.szPname)))), |
| + in_handle_(kInvalidInHandle), |
| + instance_id_(instance_id) {} |
| - static std::vector<std::unique_ptr<InPort>> EnumerateActivePorts() { |
| + static std::vector<std::unique_ptr<InPort>> EnumerateActivePorts( |
| + int instance_id) { |
| std::vector<std::unique_ptr<InPort>> ports; |
| const UINT num_devices = midiInGetNumDevs(); |
| for (UINT device_id = 0; device_id < num_devices; ++device_id) { |
| @@ -175,11 +211,17 @@ class DynamicallyInitializedMidiManagerWin::InPort final : public Port { |
| LOG(ERROR) << "midiInGetDevCaps fails on device " << device_id; |
| continue; |
| } |
| - ports.push_back(base::MakeUnique<InPort>(device_id, caps)); |
| + ports.push_back(base::MakeUnique<InPort>(instance_id, device_id, caps)); |
| } |
| return ports; |
| } |
| + void Finalize(scoped_refptr<base::SingleThreadTaskRunner> runner) { |
| + if (in_handle_ != kInvalidInHandle) { |
| + runner->PostTask(FROM_HERE, base::Bind(&FinalizeInPort, in_handle_)); |
| + } |
| + } |
| + |
| void NotifyPortStateSet(DynamicallyInitializedMidiManagerWin* manager) { |
| manager->PostReplyTask( |
| base::Bind(&DynamicallyInitializedMidiManagerWin::SetInputPortState, |
| @@ -191,6 +233,22 @@ class DynamicallyInitializedMidiManagerWin::InPort final : public Port { |
| base::Bind(&DynamicallyInitializedMidiManagerWin::AddInputPort, |
| base::Unretained(manager), info_)); |
| } |
| + |
| + // Port overrides: |
| + void Open() override { |
| + MMRESULT result = |
| + midiInOpen(&in_handle_, device_id_, |
| + reinterpret_cast<DWORD_PTR>(&HandleMidiInCallback), |
| + instance_id_, CALLBACK_FUNCTION); |
| + if (result == MMSYSERR_NOERROR) |
| + Port::Open(); |
| + else |
| + Disconnect(); |
| + } |
| + |
| + private: |
| + HMIDIIN in_handle_; |
| + int instance_id_; |
| }; |
| // TODO(toyoshim): Following patches will implement actual functions. |
| @@ -204,7 +262,8 @@ class DynamicallyInitializedMidiManagerWin::OutPort final : public Port { |
| caps.vDriverVersion, |
| base::WideToUTF8( |
| base::string16(caps.szPname, wcslen(caps.szPname)))), |
| - software_(caps.wTechnology == MOD_SWSYNTH) {} |
| + software_(caps.wTechnology == MOD_SWSYNTH), |
| + out_handle_(kInvalidOutHandle) {} |
| static std::vector<std::unique_ptr<OutPort>> EnumerateActivePorts() { |
| std::vector<std::unique_ptr<OutPort>> ports; |
| @@ -222,19 +281,11 @@ class DynamicallyInitializedMidiManagerWin::OutPort final : public Port { |
| return ports; |
| } |
| - // Port overrides: |
| - bool Connect() override { |
| - // Until |software| option is supported, disable Microsoft GS Wavetable |
| - // Synth that has a known security issue. |
| - if (software_ && manufacturer_id_ == MM_MICROSOFT && |
| - (product_id_ == MM_MSFT_WDMAUDIO_MIDIOUT || |
| - product_id_ == MM_MSFT_GENERIC_MIDISYNTH)) { |
| - return false; |
| - } |
| - return Port::Connect(); |
| + void Finalize(scoped_refptr<base::SingleThreadTaskRunner> runner) { |
| + if (out_handle_ != kInvalidOutHandle) |
| + runner->PostTask(FROM_HERE, base::Bind(&FinalizeOutPort, out_handle_)); |
| } |
| - // Port Overrides: |
|
Takashi Toyoshima
2017/02/21 05:54:28
I forgot to remove this stale line.
|
| void NotifyPortStateSet(DynamicallyInitializedMidiManagerWin* manager) { |
| manager->PostReplyTask( |
| base::Bind(&DynamicallyInitializedMidiManagerWin::SetOutputPortState, |
| @@ -247,7 +298,33 @@ class DynamicallyInitializedMidiManagerWin::OutPort final : public Port { |
| base::Unretained(manager), info_)); |
| } |
| + // Port overrides: |
| + bool Connect() override { |
|
Takashi Toyoshima
2017/02/21 05:54:28
Connect() method is just replaced here so that we
|
| + // Until |software| option is supported, disable Microsoft GS Wavetable |
| + // Synth that has a known security issue. |
| + if (software_ && manufacturer_id_ == MM_MICROSOFT && |
| + (product_id_ == MM_MSFT_WDMAUDIO_MIDIOUT || |
| + product_id_ == MM_MSFT_GENERIC_MIDISYNTH)) { |
| + return false; |
| + } |
| + return Port::Connect(); |
| + } |
| + |
| + void Open() override { |
| + MMRESULT result = |
| + midiOutOpen(&out_handle_, device_id_, |
| + reinterpret_cast<DWORD_PTR>(&HandleMidiOutCallback), 0, |
| + CALLBACK_FUNCTION); |
| + if (result == MMSYSERR_NOERROR) { |
| + Port::Open(); |
| + } else { |
| + out_handle_ = kInvalidOutHandle; |
| + Disconnect(); |
| + } |
| + } |
| + |
| const bool software_; |
| + HMIDIOUT out_handle_; |
| }; |
| DynamicallyInitializedMidiManagerWin::DynamicallyInitializedMidiManagerWin( |
| @@ -305,6 +382,15 @@ void DynamicallyInitializedMidiManagerWin::Finalize() { |
| // Tasks that did not started yet will do nothing after invalidate the |
| // instance ID above. |
| base::AutoLock lock(*GetTaskLock()); |
| + |
| + // Posts tasks that finalize each device port without MidiManager instance |
| + // on TaskRunner. If another MidiManager instance is created, its |
| + // initialization runs on the same task runner after all tasks posted here |
| + // finish. |
| + for (const auto& port : input_ports_) |
| + port->Finalize(service()->GetTaskRunner(kTaskRunner)); |
| + for (const auto& port : output_ports_) |
| + port->Finalize(service()->GetTaskRunner(kTaskRunner)); |
| } |
| void DynamicallyInitializedMidiManagerWin::DispatchSendMidiData( |
| @@ -349,7 +435,7 @@ void DynamicallyInitializedMidiManagerWin::InitializeOnTaskRunner() { |
| void DynamicallyInitializedMidiManagerWin::UpdateDeviceListOnTaskRunner() { |
| std::vector<std::unique_ptr<InPort>> active_input_ports = |
| - InPort::EnumerateActivePorts(); |
| + InPort::EnumerateActivePorts(instance_id_); |
| ReflectActiveDeviceList(this, &input_ports_, &active_input_ports); |
| std::vector<std::unique_ptr<OutPort>> active_output_ports = |