Chromium Code Reviews| Index: media/midi/midi_manager_win.cc |
| diff --git a/media/midi/midi_manager_win.cc b/media/midi/midi_manager_win.cc |
| index 926fe291483348d45310b2b285b90c9c2b8198ab..64c6a21548f582e002ffc3773b9142eb75623579 100644 |
| --- a/media/midi/midi_manager_win.cc |
| +++ b/media/midi/midi_manager_win.cc |
| @@ -5,7 +5,6 @@ |
| #include "media/midi/midi_manager_win.h" |
| #include <windows.h> |
| -#include <dbt.h> |
| #include <ks.h> |
| #include <ksmedia.h> |
| #include <mmreg.h> |
| @@ -36,6 +35,7 @@ |
| #include "base/strings/string_piece.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| +#include "base/system_monitor/system_monitor.h" |
| #include "base/threading/thread.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/timer/timer.h" |
| @@ -49,17 +49,12 @@ |
| namespace media { |
| namespace { |
| -const wchar_t kWindowClassName[] = L"ChromeMidiDeviceMonitorWindow"; |
| -const int kOnDeviceArrivalDelayMilliSec = 500; |
| static const size_t kBufferLength = 32 * 1024; |
| // We assume that nullpter represents an invalid MIDI handle. |
| const HMIDIIN kInvalidMidiInHandle = nullptr; |
| const HMIDIOUT kInvalidMidiOutHandle = nullptr; |
| -// Note that |RegisterDeviceNotificationW| returns nullptr as an invalid handle. |
| -const HDEVNOTIFY kInvalidDeviceNotifyHandle = nullptr; |
| - |
| std::string GetInErrorMessage(MMRESULT result) { |
| wchar_t text[MAXERRORLENGTH]; |
| MMRESULT get_result = midiInGetErrorText(result, text, arraysize(text)); |
| @@ -291,8 +286,10 @@ struct MidiDeviceInfo final { |
| }; |
| std::string GetManufacturerName(const MidiDeviceInfo& info) { |
| - if (info.is_usb_device) |
| - return device::UsbIds::GetVendorName(info.usb_vendor_id); |
| + if (info.is_usb_device) { |
| + const char* name = device::UsbIds::GetVendorName(info.usb_vendor_id); |
| + return std::string(name ? name : ""); |
| + } |
| switch (info.manufacturer_id) { |
| case MM_MICROSOFT: |
| @@ -308,67 +305,6 @@ using PortNumberCache = base::hash_map< |
| std::priority_queue<uint32, std::vector<uint32>, std::greater<uint32>>, |
| MidiDeviceInfo::Hasher>; |
| -class DeviceMonitorWindow final { |
| - public: |
| - explicit DeviceMonitorWindow(base::Closure on_device_arrival) |
| - : on_device_arrival_(on_device_arrival), |
| - dev_notify_handle_(kInvalidDeviceNotifyHandle) { |
| - window_.reset(new base::win::MessageWindow); |
| - if (!window_->CreateNamed(base::Bind(&DeviceMonitorWindow::HandleMessage, |
| - base::Unretained(this)), |
| - base::string16(kWindowClassName))) { |
| - LOG(ERROR) << "Failed to create message window: " << kWindowClassName; |
| - window_.reset(); |
| - } |
| - DEV_BROADCAST_DEVICEINTERFACE kBloadcastRequest = { |
| - sizeof(DEV_BROADCAST_DEVICEINTERFACE), DBT_DEVTYP_DEVICEINTERFACE, |
| - }; |
| - dev_notify_handle_ = RegisterDeviceNotificationW( |
| - window_->hwnd(), &kBloadcastRequest, |
| - DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); |
| - } |
| - |
| - ~DeviceMonitorWindow() { |
| - if (dev_notify_handle_ != kInvalidDeviceNotifyHandle) { |
| - BOOL result = UnregisterDeviceNotification(dev_notify_handle_); |
| - if (!result) { |
| - const DWORD last_error = GetLastError(); |
| - DLOG(ERROR) << "UnregisterDeviceNotification failed. error: " |
| - << last_error; |
| - } |
| - dev_notify_handle_ = kInvalidDeviceNotifyHandle; |
| - } |
| - } |
| - |
| - private: |
| - bool HandleMessage(UINT message, |
| - WPARAM wparam, |
| - LPARAM lparam, |
| - LRESULT* result) { |
| - if (message == WM_DEVICECHANGE) { |
| - switch (wparam) { |
| - case DBT_DEVICEARRIVAL: { |
| - device_arrival_timer_.Stop(); |
| - device_arrival_timer_.Start( |
| - FROM_HERE, |
| - base::TimeDelta::FromMilliseconds(kOnDeviceArrivalDelayMilliSec), |
| - on_device_arrival_); |
| - break; |
| - } |
| - } |
| - } |
| - return false; |
| - } |
| - |
| - base::Closure on_device_arrival_; |
| - base::OneShotTimer<DeviceMonitorWindow> device_arrival_timer_; |
| - base::ThreadChecker thread_checker_; |
| - scoped_ptr<base::win::MessageWindow> window_; |
| - HDEVNOTIFY dev_notify_handle_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(DeviceMonitorWindow); |
| -}; |
| - |
| struct MidiInputDeviceState final : base::RefCounted<MidiInputDeviceState> { |
| explicit MidiInputDeviceState(const MidiDeviceInfo& device_info) |
| : device_info(device_info), |
| @@ -423,29 +359,27 @@ struct MidiOutputDeviceState final : base::RefCounted<MidiOutputDeviceState> { |
| // The core logic of MIDI device handling for Windows. Basically this class is |
| // shared among following 4 threads: |
| -// 1. Device Monitor Thread |
| +// 1. Chrome IO Thread |
| // 2. OS Multimedia Thread |
| -// 3. Misc. Task Thread |
| +// 3. Task Thread |
| // 4. Sender Thread |
| // |
| -// Device Monitor Thread: |
| -// This is a standalone UI thread that is dedicated for a message-only window |
| -// which will receive WM_DEVICECHANGE Win32 message whose |
| -// wParam == DBT_DEVICEARRIVAL. This event will be used as the trigger to open |
| -// all the new MIDI devices. Note that in the current implementation we will |
| -// try to open all the existing devices in practice. This is OK because trying |
| -// to reopen a MIDI device that is already opened would simply fail, and there |
| -// is no unwilling side effect. Note also that this thread isn't responsible |
| -// for updating the device database. It will be handled by MIM_OPEN/MOM_OPEN |
| -// events dispatched to OS Multimedia Thread. |
| +// Chrome IO Thread: |
| +// MidiManager runs on Chrome IO thread. Device change notification is |
| +// delivered to the thread through the SystemMonitor service. |
| +// OnDevicesChanged() callback is invoked to update the MIDI device list. |
| +// Note that in the current implementation we will try to open all the |
| +// existing devices in practice. This is OK because trying to reopen a MIDI |
| +// device that is already opened would simply fail, and there is no unwilling |
| +// side effect. |
| // |
| // OS Multimedia Thread: |
| // This thread is maintained by the OS as a part of MIDI runtime, and |
| // responsible for receiving all the system initiated events such as device |
| -// open and close. For performance reasons, most of potentially blocking |
| -// operations will be dispatched into Misc. Task Thread. |
| +// close, and receiving data. For performance reasons, most of potentially |
| +// blocking operations will be dispatched into Task Thread. |
| // |
| -// Misc. Task Thread: |
| +// Task Thread: |
| // This thread will be used to call back following methods of MidiManager. |
| // - MidiManager::CompleteInitialization |
| // - MidiManager::AddInputPort |
| @@ -456,28 +390,27 @@ struct MidiOutputDeviceState final : base::RefCounted<MidiOutputDeviceState> { |
| // |
| // Sender Thread: |
| // This thread will be used to call Win32 APIs to send MIDI message at the |
| -// specified time. We don't want to call MIDI send APIs on Misc. Task Thread |
| +// specified time. We don't want to call MIDI send APIs on Task Thread |
| // because those APIs could be performed synchronously, hence they could block |
| // the caller thread for a while. See the comment in |
| // SendLongMidiMessageInternal for details. Currently we expect that the |
| // blocking time would be less than 1 second. |
| -class MidiServiceWinImpl : public MidiServiceWin { |
| +class MidiServiceWinImpl : public MidiServiceWin, |
| + public base::SystemMonitor::DevicesChangedObserver { |
| public: |
| MidiServiceWinImpl() |
| : delegate_(nullptr), |
| - monitor_thread_("Windows MIDI device monitor thread"), |
| sender_thread_("Windows MIDI sender thread"), |
| task_thread_("Windows MIDI task thread"), |
| destructor_started(false) {} |
| ~MidiServiceWinImpl() final { |
| + // Start() and Stop() of the threads, and AddDevicesChangeObserver() and |
| + // RemoveDevicesChangeObserver() should be called on the same thread. |
| + CHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); |
|
yukawa
2015/04/06 20:18:48
optional: We could update |destructor_started| fir
Takashi Toyoshima
2015/04/07 06:19:29
Oh, good catch. That's a good thing to be fixed.
I
|
| destructor_started = true; |
| - if (monitor_thread_.IsRunning()) { |
| - monitor_thread_.message_loop()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&MidiServiceWinImpl::StopDeviceMonitorOnMonitorThreadSync, |
| - base::Unretained(this))); |
| - } |
| { |
| std::vector<HMIDIIN> input_devices; |
| { |
| @@ -520,23 +453,32 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| } |
| } |
| } |
| - monitor_thread_.Stop(); |
| sender_thread_.Stop(); |
| task_thread_.Stop(); |
| } |
| // MidiServiceWin overrides: |
| void InitializeAsync(MidiServiceWinDelegate* delegate) final { |
| + // Start() and Stop() of the threads, and AddDevicesChangeObserver() and |
| + // RemoveDevicesChangeObserver() should be called on the same thread. |
| + CHECK(thread_checker_.CalledOnValidThread()); |
| + |
| delegate_ = delegate; |
| - sender_thread_.StartWithOptions( |
| - base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
| - task_thread_.StartWithOptions( |
| - base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
| - monitor_thread_.StartWithOptions( |
| - base::Thread::Options(base::MessageLoop::TYPE_UI, 0)); |
| - monitor_thread_.message_loop()->PostTask( |
| - FROM_HERE, base::Bind(&MidiServiceWinImpl::InitializeOnMonitorThread, |
| - base::Unretained(this))); |
| + |
| + sender_thread_.Start(); |
| + task_thread_.Start(); |
| + |
| + // Start monitoring device changes. This should start before the |
| + // following UpdateDeviceList() call not to miss the event happening |
| + // between the call and the observer registration. |
| + base::SystemMonitor::Get()->AddDevicesChangedObserver(this); |
| + |
| + UpdateDeviceList(); |
| + |
| + task_thread_.message_loop()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MidiServiceWinImpl::CompleteInitializationOnTaskThread, |
| + base::Unretained(this), MIDI_OK)); |
| } |
| void SendMidiDataAsync(uint32 port_number, |
| @@ -574,6 +516,22 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| } |
| } |
| + // base::SystemMonitor::DevicesChangedObserver overrides: |
| + void OnDevicesChanged(base::SystemMonitor::DeviceType device_type) final { |
| + CHECK(thread_checker_.CalledOnValidThread()); |
| + switch (device_type) { |
| + case base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE: |
| + case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE: |
| + // Add case of other unrelated device types here. |
| + return; |
| + case base::SystemMonitor::DEVTYPE_UNKNOWN: |
| + // Interested in MIDI devices. Try updating the device list. |
| + UpdateDeviceList(); |
| + break; |
| + // No default here to capture new DeviceType by compile time. |
| + } |
| + } |
| + |
| private: |
| scoped_refptr<MidiInputDeviceState> GetInputDeviceFromHandle( |
| HMIDIIN midi_handle) { |
| @@ -597,21 +555,28 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| return output_ports_[port_number]; |
| } |
| + void UpdateDeviceList() { |
| + task_thread_.message_loop()->PostTask( |
| + FROM_HERE, base::Bind(&MidiServiceWinImpl::UpdateDeviceListOnTaskThread, |
| + base::Unretained(this))); |
| + } |
| + |
| ///////////////////////////////////////////////////////////////////////////// |
| // Callbacks on the OS multimedia thread. |
| ///////////////////////////////////////////////////////////////////////////// |
| - static void CALLBACK OnMidiInEventOnMultimediaThread(HMIDIIN midi_in_handle, |
| - UINT message, |
| - DWORD_PTR instance, |
| - DWORD_PTR param1, |
| - DWORD_PTR param2) { |
| + static void CALLBACK |
| + OnMidiInEventOnMainlyMultimediaThread(HMIDIIN midi_in_handle, |
| + UINT message, |
| + DWORD_PTR instance, |
| + DWORD_PTR param1, |
| + DWORD_PTR param2) { |
| MidiServiceWinImpl* self = reinterpret_cast<MidiServiceWinImpl*>(instance); |
| if (!self) |
| return; |
| switch (message) { |
| case MIM_OPEN: |
| - self->OnMidiInOpenOnMultimediaThread(midi_in_handle); |
| + self->OnMidiInOpen(midi_in_handle); |
| break; |
| case MIM_DATA: |
| self->OnMidiInDataOnMultimediaThread(midi_in_handle, param1, param2); |
| @@ -621,12 +586,13 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| param2); |
| break; |
| case MIM_CLOSE: |
| + LOG(ERROR) << "MIM_CLOSE"; |
|
Takashi Toyoshima
2015/04/06 20:03:09
oops, this is mistakenly merged from local debuggi
yukawa
2015/04/06 20:18:48
Is this a debug code?
|
| self->OnMidiInCloseOnMultimediaThread(midi_in_handle); |
| break; |
| } |
| } |
| - void OnMidiInOpenOnMultimediaThread(HMIDIIN midi_in_handle) { |
| + void OnMidiInOpen(HMIDIIN midi_in_handle) { |
| UINT device_id = 0; |
| MMRESULT result = midiInGetID(midi_in_handle, &device_id); |
| if (result != MMSYSERR_NOERROR) { |
| @@ -785,17 +751,17 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| } |
| static void CALLBACK |
| - OnMidiOutEventOnMultimediaThread(HMIDIOUT midi_out_handle, |
| - UINT message, |
| - DWORD_PTR instance, |
| - DWORD_PTR param1, |
| - DWORD_PTR param2) { |
| + OnMidiOutEventOnMainlyMultimediaThread(HMIDIOUT midi_out_handle, |
| + UINT message, |
| + DWORD_PTR instance, |
| + DWORD_PTR param1, |
| + DWORD_PTR param2) { |
| MidiServiceWinImpl* self = reinterpret_cast<MidiServiceWinImpl*>(instance); |
| if (!self) |
| return; |
| switch (message) { |
| case MOM_OPEN: |
| - self->OnMidiOutOpenOnMultimediaThread(midi_out_handle, param1, param2); |
| + self->OnMidiOutOpen(midi_out_handle, param1, param2); |
| break; |
| case MOM_DONE: |
| self->OnMidiOutDoneOnMultimediaThread(midi_out_handle, param1); |
| @@ -806,9 +772,9 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| } |
| } |
| - void OnMidiOutOpenOnMultimediaThread(HMIDIOUT midi_out_handle, |
| - DWORD_PTR param1, |
| - DWORD_PTR param2) { |
| + void OnMidiOutOpen(HMIDIOUT midi_out_handle, |
| + DWORD_PTR param1, |
| + DWORD_PTR param2) { |
| UINT device_id = 0; |
| MMRESULT result = midiOutGetID(midi_out_handle, &device_id); |
| if (result != MMSYSERR_NOERROR) { |
| @@ -906,95 +872,6 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| } |
| ///////////////////////////////////////////////////////////////////////////// |
| - // Callbacks on the monitor thread. |
| - ///////////////////////////////////////////////////////////////////////////// |
| - |
| - void AssertOnMonitorThread() { |
| - DCHECK_EQ(monitor_thread_.thread_id(), base::PlatformThread::CurrentId()); |
| - } |
| - |
| - void InitializeOnMonitorThread() { |
| - AssertOnMonitorThread(); |
| - // Synchronously open all the existing MIDI devices. |
| - TryOpenAllDevicesOnMonitorThreadSync(); |
| - // Since |TryOpenAllDevicesOnMonitorThreadSync()| is a blocking call, it is |
| - // guaranteed that all the initial MIDI ports are already opened here, and |
| - // corresponding tasks to call |AddInputPortOnTaskThread()| and |
| - // |AddOutputPortOnTaskThread()| are already queued in the Misc. Task |
| - // Thread. This means that the following task to call |
| - // |CompleteInitializationOnTaskThread()| are always called after all the |
| - // pending tasks to call |AddInputPortOnTaskThread()| and |
| - // |AddOutputPortOnTaskThread()| are completed. |
| - task_thread_.message_loop()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&MidiServiceWinImpl::CompleteInitializationOnTaskThread, |
| - base::Unretained(this), MIDI_OK)); |
| - // Start monitoring based on notifications generated by |
| - // RegisterDeviceNotificationW API. |
| - device_monitor_window_.reset(new DeviceMonitorWindow( |
| - base::Bind(&MidiServiceWinImpl::TryOpenAllDevicesOnMonitorThreadSync, |
| - base::Unretained(this)))); |
| - } |
| - |
| - void StopDeviceMonitorOnMonitorThreadSync() { |
| - device_monitor_window_.reset(); |
| - } |
| - |
| - // Note that this is a blocking method. |
| - void TryOpenAllDevicesOnMonitorThreadSync() { |
| - AssertOnMonitorThread(); |
| - const UINT num_in_devices = midiInGetNumDevs(); |
| - for (UINT device_id = 0; device_id < num_in_devices; ++device_id) { |
| - // Here we use |CALLBACK_FUNCTION| to subscribe MIM_DATA, MIM_LONGDATA, |
| - // MIM_OPEN, and MIM_CLOSE events. |
| - // - MIM_DATA: This is the only way to get a short MIDI message with |
| - // timestamp information. |
| - // - MIM_LONGDATA: This is the only way to get a long MIDI message with |
| - // timestamp information. |
| - // - MIM_OPEN: This event is sent the input device is opened. |
| - // - MIM_CLOSE: This event is sent when 1) midiInClose() is called, or 2) |
| - // the MIDI device becomes unavailable for some reasons, e.g., the |
| - // cable is disconnected. As for the former case, HMIDIOUT will be |
| - // invalidated soon after the callback is finished. As for the later |
| - // case, however, HMIDIOUT continues to be valid until midiInClose() |
| - // is called. |
| - HMIDIIN midi_handle = kInvalidMidiInHandle; |
| - const MMRESULT result = midiInOpen( |
| - &midi_handle, device_id, |
| - reinterpret_cast<DWORD_PTR>(&OnMidiInEventOnMultimediaThread), |
| - reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION); |
| - DLOG_IF(ERROR, result != MMSYSERR_NOERROR && result != MMSYSERR_ALLOCATED) |
| - << "Failed to open output device. " |
| - << " id: " << device_id << " message: " << GetInErrorMessage(result); |
| - } |
| - |
| - const UINT num_out_devices = midiOutGetNumDevs(); |
| - for (UINT device_id = 0; device_id < num_out_devices; ++device_id) { |
| - // Here we use |CALLBACK_FUNCTION| to subscribe MOM_DONE, MOM_OPEN, and |
| - // MOM_CLOSE events. |
| - // - MOM_DONE: SendLongMidiMessageInternal() relies on this event to clean |
| - // up the backing store where a long MIDI message is stored. |
| - // - MOM_OPEN: This event is sent the output device is opened. |
| - // - MOM_CLOSE: This event is sent when 1) midiOutClose() is called, or 2) |
| - // the MIDI device becomes unavailable for some reasons, e.g., the |
| - // cable is disconnected. As for the former case, HMIDIOUT will be |
| - // invalidated soon after the callback is finished. As for the later |
| - // case, however, HMIDIOUT continues to be valid until midiOutClose() |
| - // is called. |
| - HMIDIOUT midi_handle = kInvalidMidiOutHandle; |
| - const MMRESULT result = midiOutOpen( |
| - &midi_handle, device_id, |
| - reinterpret_cast<DWORD_PTR>(&OnMidiOutEventOnMultimediaThread), |
| - reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION); |
| - if (result != MMSYSERR_NOERROR && result != MMSYSERR_ALLOCATED) { |
| - DLOG(ERROR) << "Failed to open output device. " |
| - << " id: " << device_id |
| - << " message: " << GetOutErrorMessage(result); |
| - } |
| - } |
| - } |
| - |
| - ///////////////////////////////////////////////////////////////////////////// |
| // Callbacks on the sender thread. |
| ///////////////////////////////////////////////////////////////////////////// |
| @@ -1058,6 +935,59 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| DCHECK_EQ(task_thread_.thread_id(), base::PlatformThread::CurrentId()); |
| } |
| + void UpdateDeviceListOnTaskThread() { |
| + AssertOnTaskThread(); |
| + const UINT num_in_devices = midiInGetNumDevs(); |
| + for (UINT device_id = 0; device_id < num_in_devices; ++device_id) { |
| + // Here we use |CALLBACK_FUNCTION| to subscribe MIM_DATA, MIM_LONGDATA, |
| + // MIM_OPEN, and MIM_CLOSE events. |
| + // - MIM_DATA: This is the only way to get a short MIDI message with |
| + // timestamp information. |
| + // - MIM_LONGDATA: This is the only way to get a long MIDI message with |
| + // timestamp information. |
| + // - MIM_OPEN: This event is sent the input device is opened. Note that |
| + // this message is called on the caller thread. |
| + // - MIM_CLOSE: This event is sent when 1) midiInClose() is called, or 2) |
| + // the MIDI device becomes unavailable for some reasons, e.g., the |
| + // cable is disconnected. As for the former case, HMIDIOUT will be |
| + // invalidated soon after the callback is finished. As for the later |
| + // case, however, HMIDIOUT continues to be valid until midiInClose() |
| + // is called. |
| + HMIDIIN midi_handle = kInvalidMidiInHandle; |
| + const MMRESULT result = midiInOpen( |
| + &midi_handle, device_id, |
| + reinterpret_cast<DWORD_PTR>(&OnMidiInEventOnMainlyMultimediaThread), |
| + reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION); |
| + DLOG_IF(ERROR, result != MMSYSERR_NOERROR && result != MMSYSERR_ALLOCATED) |
| + << "Failed to open output device. " |
| + << " id: " << device_id << " message: " << GetInErrorMessage(result); |
| + } |
| + |
| + const UINT num_out_devices = midiOutGetNumDevs(); |
| + for (UINT device_id = 0; device_id < num_out_devices; ++device_id) { |
| + // Here we use |CALLBACK_FUNCTION| to subscribe MOM_DONE, MOM_OPEN, and |
| + // MOM_CLOSE events. |
| + // - MOM_DONE: SendLongMidiMessageInternal() relies on this event to clean |
| + // up the backing store where a long MIDI message is stored. |
| + // - MOM_OPEN: This event is sent the output device is opened. Note that |
| + // this message is called on the caller thread. |
| + // - MOM_CLOSE: This event is sent when 1) midiOutClose() is called, or 2) |
| + // the MIDI device becomes unavailable for some reasons, e.g., the |
| + // cable is disconnected. As for the former case, HMIDIOUT will be |
| + // invalidated soon after the callback is finished. As for the later |
| + // case, however, HMIDIOUT continues to be valid until midiOutClose() |
| + // is called. |
| + HMIDIOUT midi_handle = kInvalidMidiOutHandle; |
| + const MMRESULT result = midiOutOpen( |
| + &midi_handle, device_id, |
| + reinterpret_cast<DWORD_PTR>(&OnMidiOutEventOnMainlyMultimediaThread), |
| + reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION); |
| + DLOG_IF(ERROR, result != MMSYSERR_NOERROR && result != MMSYSERR_ALLOCATED) |
| + << "Failed to open output device. " |
| + << " id: " << device_id << " message: " << GetOutErrorMessage(result); |
| + } |
| + } |
| + |
| void StartInputDeviceOnTaskThread(HMIDIIN midi_in_handle) { |
| AssertOnTaskThread(); |
| auto state = GetInputDeviceFromHandle(midi_in_handle); |
| @@ -1127,12 +1057,11 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| // Does not take ownership. |
| MidiServiceWinDelegate* delegate_; |
| - base::Thread monitor_thread_; |
| + base::ThreadChecker thread_checker_; |
| + |
| base::Thread sender_thread_; |
| base::Thread task_thread_; |
| - scoped_ptr<DeviceMonitorWindow> device_monitor_window_; |
| - |
| base::Lock input_ports_lock_; |
| base::hash_map<HMIDIIN, scoped_refptr<MidiInputDeviceState>> |
| input_device_map_; // GUARDED_BY(input_ports_lock_) |
| @@ -1151,7 +1080,7 @@ class MidiServiceWinImpl : public MidiServiceWin { |
| // True if one thread reached MidiServiceWinImpl::~MidiServiceWinImpl(). Note |
| // that MidiServiceWinImpl::~MidiServiceWinImpl() is blocked until |
| - // |monitor_thread_|, |sender_thread_|, and |task_thread_| are stopped. |
| + // |sender_thread_|, and |task_thread_| are stopped. |
| // This flag can be used as the signal that when background tasks must be |
| // interrupted. |
| // TODO(toyoshim): Use std::atomic<bool> when it is allowed. |