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

Unified Diff: media/midi/dynamically_initialized_midi_manager_win.cc

Issue 2701503005: Web MIDI: device open/close for dynamic manager instantiation on Windows (Closed)
Patch Set: rebase Created 3 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 =
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698