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

Unified Diff: media/midi/midi_manager_win.cc

Issue 1056333002: Web MIDI: Improve device change monitornig on Windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: SystemMonitor in test Created 5 years, 8 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 | « media/midi/midi_manager_unittest.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..a911ff6d5f371dcc93c4a4bda5ad357bdc566af5 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());
+
destructor_started = true;
- if (monitor_thread_.IsRunning()) {
- monitor_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&MidiServiceWinImpl::StopDeviceMonitorOnMonitorThreadSync,
- base::Unretained(this)));
- }
+ base::SystemMonitor::Get()->RemoveDevicesChangedObserver(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,25 @@ class MidiServiceWinImpl : public MidiServiceWin {
}
}
+ // base::SystemMonitor::DevicesChangedObserver overrides:
+ void OnDevicesChanged(base::SystemMonitor::DeviceType device_type) final {
+ CHECK(thread_checker_.CalledOnValidThread());
+ if (destructor_started)
+ return;
+
+ 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 +558,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);
@@ -626,7 +594,7 @@ class MidiServiceWinImpl : public MidiServiceWin {
}
}
- 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 +753,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 +774,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 +874,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 +937,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 +1059,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 +1082,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.
« no previous file with comments | « media/midi/midi_manager_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698