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

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: build fix 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..2cb1fc1d2ad435f353c4904442423794d51f278b 100644
--- a/media/midi/dynamically_initialized_midi_manager_win.cc
+++ b/media/midi/dynamically_initialized_midi_manager_win.cc
@@ -26,6 +26,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 +73,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,
@@ -162,7 +193,8 @@ class DynamicallyInitializedMidiManagerWin::InPort final : public Port {
caps.wPid,
caps.vDriverVersion,
base::WideToUTF8(
- base::string16(caps.szPname, wcslen(caps.szPname)))) {}
+ base::string16(caps.szPname, wcslen(caps.szPname)))),
+ in_handle_(kInvalidInHandle) {}
static std::vector<std::unique_ptr<InPort>> EnumerateActivePorts() {
std::vector<std::unique_ptr<InPort>> ports;
@@ -180,6 +212,12 @@ class DynamicallyInitializedMidiManagerWin::InPort final : public Port {
return ports;
}
+ void Finalize(scoped_refptr<base::SingleThreadTaskRunner> runner) {
Takashi Toyoshima 2017/02/22 10:00:23 Finalize() runs on the I/O thread, and others run
Takashi Toyoshima 2017/02/23 02:42:45 Ah, no. Now I remember that this was intentional.
Takashi Toyoshima 2017/02/23 03:01:42 https://codereview.chromium.org/2686043003/diff/14
+ 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 +229,32 @@ class DynamicallyInitializedMidiManagerWin::InPort final : public Port {
base::Bind(&DynamicallyInitializedMidiManagerWin::AddInputPort,
base::Unretained(manager), info_));
}
+
+ // Port overrides:
+ bool Disconnect() override {
+ if (in_handle_ != kInvalidInHandle) {
+ // Following API call may fail because device was already disconnected.
+ // But just in case.
+ midiInClose(in_handle_);
+ in_handle_ = kInvalidInHandle;
+ }
+ return Port::Disconnect();
+ }
+
+ void Open() override {
+ // TODO(toyoshim): Pass instance_id to implement HandleMidiInCallback.
+ MMRESULT result =
+ midiInOpen(&in_handle_, device_id_,
+ reinterpret_cast<DWORD_PTR>(&HandleMidiInCallback), 0,
+ CALLBACK_FUNCTION);
+ if (result == MMSYSERR_NOERROR)
+ Port::Open();
+ else
+ Disconnect();
+ }
+
+ private:
+ HMIDIIN in_handle_;
};
// TODO(toyoshim): Following patches will implement actual functions.
@@ -204,7 +268,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,6 +287,23 @@ class DynamicallyInitializedMidiManagerWin::OutPort final : public Port {
return ports;
}
+ void Finalize(scoped_refptr<base::SingleThreadTaskRunner> runner) {
+ if (out_handle_ != kInvalidOutHandle)
+ runner->PostTask(FROM_HERE, base::Bind(&FinalizeOutPort, out_handle_));
+ }
+
+ void NotifyPortStateSet(DynamicallyInitializedMidiManagerWin* manager) {
+ manager->PostReplyTask(
+ base::Bind(&DynamicallyInitializedMidiManagerWin::SetOutputPortState,
+ base::Unretained(manager), index_, info_.state));
+ }
+
+ void NotifyPortAdded(DynamicallyInitializedMidiManagerWin* manager) {
+ manager->PostReplyTask(
+ base::Bind(&DynamicallyInitializedMidiManagerWin::AddOutputPort,
+ base::Unretained(manager), info_));
+ }
+
// Port overrides:
bool Connect() override {
// Until |software| option is supported, disable Microsoft GS Wavetable
@@ -234,20 +316,31 @@ class DynamicallyInitializedMidiManagerWin::OutPort final : public Port {
return Port::Connect();
}
- // Port Overrides:
- void NotifyPortStateSet(DynamicallyInitializedMidiManagerWin* manager) {
- manager->PostReplyTask(
- base::Bind(&DynamicallyInitializedMidiManagerWin::SetOutputPortState,
- base::Unretained(manager), index_, info_.state));
+ bool Disconnect() override {
+ if (out_handle_ != kInvalidOutHandle) {
+ // Following API call may fail because device was already disconnected.
+ // But just in case.
+ midiOutClose(out_handle_);
+ out_handle_ = kInvalidOutHandle;
+ }
+ return Port::Disconnect();
}
- void NotifyPortAdded(DynamicallyInitializedMidiManagerWin* manager) {
- manager->PostReplyTask(
- base::Bind(&DynamicallyInitializedMidiManagerWin::AddOutputPort,
- base::Unretained(manager), info_));
+ 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 +398,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(
« 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