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 = |