Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/midi/midi_manager_win.h" | 5 #include "media/midi/midi_manager_win.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <dbt.h> | |
| 9 #include <ks.h> | 8 #include <ks.h> |
| 10 #include <ksmedia.h> | 9 #include <ksmedia.h> |
| 11 #include <mmreg.h> | 10 #include <mmreg.h> |
| 12 // Prevent unnecessary functions from being included from <mmsystem.h> | 11 // Prevent unnecessary functions from being included from <mmsystem.h> |
| 13 #define MMNODRV | 12 #define MMNODRV |
| 14 #define MMNOSOUND | 13 #define MMNOSOUND |
| 15 #define MMNOWAVE | 14 #define MMNOWAVE |
| 16 #define MMNOAUX | 15 #define MMNOAUX |
| 17 #define MMNOMIXER | 16 #define MMNOMIXER |
| 18 #define MMNOTIMER | 17 #define MMNOTIMER |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 29 #include "base/basictypes.h" | 28 #include "base/basictypes.h" |
| 30 #include "base/bind.h" | 29 #include "base/bind.h" |
| 31 #include "base/containers/hash_tables.h" | 30 #include "base/containers/hash_tables.h" |
| 32 #include "base/memory/scoped_ptr.h" | 31 #include "base/memory/scoped_ptr.h" |
| 33 #include "base/message_loop/message_loop.h" | 32 #include "base/message_loop/message_loop.h" |
| 34 #include "base/strings/string16.h" | 33 #include "base/strings/string16.h" |
| 35 #include "base/strings/string_number_conversions.h" | 34 #include "base/strings/string_number_conversions.h" |
| 36 #include "base/strings/string_piece.h" | 35 #include "base/strings/string_piece.h" |
| 37 #include "base/strings/stringprintf.h" | 36 #include "base/strings/stringprintf.h" |
| 38 #include "base/strings/utf_string_conversions.h" | 37 #include "base/strings/utf_string_conversions.h" |
| 38 #include "base/system_monitor/system_monitor.h" | |
| 39 #include "base/threading/thread.h" | 39 #include "base/threading/thread.h" |
| 40 #include "base/threading/thread_checker.h" | 40 #include "base/threading/thread_checker.h" |
| 41 #include "base/timer/timer.h" | 41 #include "base/timer/timer.h" |
| 42 #include "base/win/message_window.h" | 42 #include "base/win/message_window.h" |
| 43 #include "device/usb/usb_ids.h" | 43 #include "device/usb/usb_ids.h" |
| 44 #include "media/midi/midi_manager.h" | 44 #include "media/midi/midi_manager.h" |
| 45 #include "media/midi/midi_message_queue.h" | 45 #include "media/midi/midi_message_queue.h" |
| 46 #include "media/midi/midi_message_util.h" | 46 #include "media/midi/midi_message_util.h" |
| 47 #include "media/midi/midi_port_info.h" | 47 #include "media/midi/midi_port_info.h" |
| 48 | 48 |
| 49 namespace media { | 49 namespace media { |
| 50 namespace { | 50 namespace { |
| 51 | 51 |
| 52 const wchar_t kWindowClassName[] = L"ChromeMidiDeviceMonitorWindow"; | |
| 53 const int kOnDeviceArrivalDelayMilliSec = 500; | |
| 54 static const size_t kBufferLength = 32 * 1024; | 52 static const size_t kBufferLength = 32 * 1024; |
| 55 | 53 |
| 56 // We assume that nullpter represents an invalid MIDI handle. | 54 // We assume that nullpter represents an invalid MIDI handle. |
| 57 const HMIDIIN kInvalidMidiInHandle = nullptr; | 55 const HMIDIIN kInvalidMidiInHandle = nullptr; |
| 58 const HMIDIOUT kInvalidMidiOutHandle = nullptr; | 56 const HMIDIOUT kInvalidMidiOutHandle = nullptr; |
| 59 | 57 |
| 60 // Note that |RegisterDeviceNotificationW| returns nullptr as an invalid handle. | |
| 61 const HDEVNOTIFY kInvalidDeviceNotifyHandle = nullptr; | |
| 62 | |
| 63 std::string GetInErrorMessage(MMRESULT result) { | 58 std::string GetInErrorMessage(MMRESULT result) { |
| 64 wchar_t text[MAXERRORLENGTH]; | 59 wchar_t text[MAXERRORLENGTH]; |
| 65 MMRESULT get_result = midiInGetErrorText(result, text, arraysize(text)); | 60 MMRESULT get_result = midiInGetErrorText(result, text, arraysize(text)); |
| 66 if (get_result != MMSYSERR_NOERROR) { | 61 if (get_result != MMSYSERR_NOERROR) { |
| 67 DLOG(ERROR) << "Failed to get error message." | 62 DLOG(ERROR) << "Failed to get error message." |
| 68 << " original error: " << result | 63 << " original error: " << result |
| 69 << " midiInGetErrorText error: " << get_result; | 64 << " midiInGetErrorText error: " << get_result; |
| 70 return std::string(); | 65 return std::string(); |
| 71 } | 66 } |
| 72 return base::WideToUTF8(text); | 67 return base::WideToUTF8(text); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 284 return EXTRACT_USBAUDIO_PID(&caps.ProductGuid); | 279 return EXTRACT_USBAUDIO_PID(&caps.ProductGuid); |
| 285 } | 280 } |
| 286 static uint16 ExtractUsbProductIdIfExists(const MIDIOUTCAPS2W& caps) { | 281 static uint16 ExtractUsbProductIdIfExists(const MIDIOUTCAPS2W& caps) { |
| 287 if (!IS_COMPATIBLE_USBAUDIO_PID(&caps.ProductGuid)) | 282 if (!IS_COMPATIBLE_USBAUDIO_PID(&caps.ProductGuid)) |
| 288 return 0; | 283 return 0; |
| 289 return EXTRACT_USBAUDIO_PID(&caps.ProductGuid); | 284 return EXTRACT_USBAUDIO_PID(&caps.ProductGuid); |
| 290 } | 285 } |
| 291 }; | 286 }; |
| 292 | 287 |
| 293 std::string GetManufacturerName(const MidiDeviceInfo& info) { | 288 std::string GetManufacturerName(const MidiDeviceInfo& info) { |
| 294 if (info.is_usb_device) | 289 if (info.is_usb_device) { |
| 295 return device::UsbIds::GetVendorName(info.usb_vendor_id); | 290 const char* name = device::UsbIds::GetVendorName(info.usb_vendor_id); |
| 291 return std::string(name ? name : ""); | |
| 292 } | |
| 296 | 293 |
| 297 switch (info.manufacturer_id) { | 294 switch (info.manufacturer_id) { |
| 298 case MM_MICROSOFT: | 295 case MM_MICROSOFT: |
| 299 return "Microsoft Corporation"; | 296 return "Microsoft Corporation"; |
| 300 default: | 297 default: |
| 301 // TODO(toyoshim): Support other manufacture IDs. crbug.com/472341. | 298 // TODO(toyoshim): Support other manufacture IDs. crbug.com/472341. |
| 302 return ""; | 299 return ""; |
| 303 } | 300 } |
| 304 } | 301 } |
| 305 | 302 |
| 306 using PortNumberCache = base::hash_map< | 303 using PortNumberCache = base::hash_map< |
| 307 MidiDeviceInfo, | 304 MidiDeviceInfo, |
| 308 std::priority_queue<uint32, std::vector<uint32>, std::greater<uint32>>, | 305 std::priority_queue<uint32, std::vector<uint32>, std::greater<uint32>>, |
| 309 MidiDeviceInfo::Hasher>; | 306 MidiDeviceInfo::Hasher>; |
| 310 | 307 |
| 311 class DeviceMonitorWindow final { | |
| 312 public: | |
| 313 explicit DeviceMonitorWindow(base::Closure on_device_arrival) | |
| 314 : on_device_arrival_(on_device_arrival), | |
| 315 dev_notify_handle_(kInvalidDeviceNotifyHandle) { | |
| 316 window_.reset(new base::win::MessageWindow); | |
| 317 if (!window_->CreateNamed(base::Bind(&DeviceMonitorWindow::HandleMessage, | |
| 318 base::Unretained(this)), | |
| 319 base::string16(kWindowClassName))) { | |
| 320 LOG(ERROR) << "Failed to create message window: " << kWindowClassName; | |
| 321 window_.reset(); | |
| 322 } | |
| 323 DEV_BROADCAST_DEVICEINTERFACE kBloadcastRequest = { | |
| 324 sizeof(DEV_BROADCAST_DEVICEINTERFACE), DBT_DEVTYP_DEVICEINTERFACE, | |
| 325 }; | |
| 326 dev_notify_handle_ = RegisterDeviceNotificationW( | |
| 327 window_->hwnd(), &kBloadcastRequest, | |
| 328 DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); | |
| 329 } | |
| 330 | |
| 331 ~DeviceMonitorWindow() { | |
| 332 if (dev_notify_handle_ != kInvalidDeviceNotifyHandle) { | |
| 333 BOOL result = UnregisterDeviceNotification(dev_notify_handle_); | |
| 334 if (!result) { | |
| 335 const DWORD last_error = GetLastError(); | |
| 336 DLOG(ERROR) << "UnregisterDeviceNotification failed. error: " | |
| 337 << last_error; | |
| 338 } | |
| 339 dev_notify_handle_ = kInvalidDeviceNotifyHandle; | |
| 340 } | |
| 341 } | |
| 342 | |
| 343 private: | |
| 344 bool HandleMessage(UINT message, | |
| 345 WPARAM wparam, | |
| 346 LPARAM lparam, | |
| 347 LRESULT* result) { | |
| 348 if (message == WM_DEVICECHANGE) { | |
| 349 switch (wparam) { | |
| 350 case DBT_DEVICEARRIVAL: { | |
| 351 device_arrival_timer_.Stop(); | |
| 352 device_arrival_timer_.Start( | |
| 353 FROM_HERE, | |
| 354 base::TimeDelta::FromMilliseconds(kOnDeviceArrivalDelayMilliSec), | |
| 355 on_device_arrival_); | |
| 356 break; | |
| 357 } | |
| 358 } | |
| 359 } | |
| 360 return false; | |
| 361 } | |
| 362 | |
| 363 base::Closure on_device_arrival_; | |
| 364 base::OneShotTimer<DeviceMonitorWindow> device_arrival_timer_; | |
| 365 base::ThreadChecker thread_checker_; | |
| 366 scoped_ptr<base::win::MessageWindow> window_; | |
| 367 HDEVNOTIFY dev_notify_handle_; | |
| 368 | |
| 369 DISALLOW_COPY_AND_ASSIGN(DeviceMonitorWindow); | |
| 370 }; | |
| 371 | |
| 372 struct MidiInputDeviceState final : base::RefCounted<MidiInputDeviceState> { | 308 struct MidiInputDeviceState final : base::RefCounted<MidiInputDeviceState> { |
| 373 explicit MidiInputDeviceState(const MidiDeviceInfo& device_info) | 309 explicit MidiInputDeviceState(const MidiDeviceInfo& device_info) |
| 374 : device_info(device_info), | 310 : device_info(device_info), |
| 375 midi_handle(kInvalidMidiInHandle), | 311 midi_handle(kInvalidMidiInHandle), |
| 376 port_index(0), | 312 port_index(0), |
| 377 port_age(0), | 313 port_age(0), |
| 378 start_time_initialized(false) {} | 314 start_time_initialized(false) {} |
| 379 | 315 |
| 380 const MidiDeviceInfo device_info; | 316 const MidiDeviceInfo device_info; |
| 381 HMIDIIN midi_handle; | 317 HMIDIIN midi_handle; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 416 uint64 port_age; | 352 uint64 port_age; |
| 417 // True if the device is already closed and |midi_handle| is considered to be | 353 // True if the device is already closed and |midi_handle| is considered to be |
| 418 // invalid. | 354 // invalid. |
| 419 // TODO(toyoshim): Use std::atomic<bool> when it is allowed in Chromium | 355 // TODO(toyoshim): Use std::atomic<bool> when it is allowed in Chromium |
| 420 // project. | 356 // project. |
| 421 volatile bool closed; | 357 volatile bool closed; |
| 422 }; | 358 }; |
| 423 | 359 |
| 424 // The core logic of MIDI device handling for Windows. Basically this class is | 360 // The core logic of MIDI device handling for Windows. Basically this class is |
| 425 // shared among following 4 threads: | 361 // shared among following 4 threads: |
| 426 // 1. Device Monitor Thread | 362 // 1. Chrome IO Thread |
| 427 // 2. OS Multimedia Thread | 363 // 2. OS Multimedia Thread |
| 428 // 3. Misc. Task Thread | 364 // 3. Task Thread |
| 429 // 4. Sender Thread | 365 // 4. Sender Thread |
| 430 // | 366 // |
| 431 // Device Monitor Thread: | 367 // Chrome IO Thread: |
| 432 // This is a standalone UI thread that is dedicated for a message-only window | 368 // MidiManager runs on Chrome IO thread. Device change notification is |
| 433 // which will receive WM_DEVICECHANGE Win32 message whose | 369 // delivered to the thread through the SystemMonitor service. |
| 434 // wParam == DBT_DEVICEARRIVAL. This event will be used as the trigger to open | 370 // OnDevicesChanged() callback is invoked to update the MIDI device list. |
| 435 // all the new MIDI devices. Note that in the current implementation we will | 371 // Note that in the current implementation we will try to open all the |
| 436 // try to open all the existing devices in practice. This is OK because trying | 372 // existing devices in practice. This is OK because trying to reopen a MIDI |
| 437 // to reopen a MIDI device that is already opened would simply fail, and there | 373 // device that is already opened would simply fail, and there is no unwilling |
| 438 // is no unwilling side effect. Note also that this thread isn't responsible | 374 // side effect. |
| 439 // for updating the device database. It will be handled by MIM_OPEN/MOM_OPEN | |
| 440 // events dispatched to OS Multimedia Thread. | |
| 441 // | 375 // |
| 442 // OS Multimedia Thread: | 376 // OS Multimedia Thread: |
| 443 // This thread is maintained by the OS as a part of MIDI runtime, and | 377 // This thread is maintained by the OS as a part of MIDI runtime, and |
| 444 // responsible for receiving all the system initiated events such as device | 378 // responsible for receiving all the system initiated events such as device |
| 445 // open and close. For performance reasons, most of potentially blocking | 379 // close, and receiving data. For performance reasons, most of potentially |
| 446 // operations will be dispatched into Misc. Task Thread. | 380 // blocking operations will be dispatched into Task Thread. |
| 447 // | 381 // |
| 448 // Misc. Task Thread: | 382 // Task Thread: |
| 449 // This thread will be used to call back following methods of MidiManager. | 383 // This thread will be used to call back following methods of MidiManager. |
| 450 // - MidiManager::CompleteInitialization | 384 // - MidiManager::CompleteInitialization |
| 451 // - MidiManager::AddInputPort | 385 // - MidiManager::AddInputPort |
| 452 // - MidiManager::AddOutputPort | 386 // - MidiManager::AddOutputPort |
| 453 // - MidiManager::SetInputPortState | 387 // - MidiManager::SetInputPortState |
| 454 // - MidiManager::SetOutputPortState | 388 // - MidiManager::SetOutputPortState |
| 455 // - MidiManager::ReceiveMidiData | 389 // - MidiManager::ReceiveMidiData |
| 456 // | 390 // |
| 457 // Sender Thread: | 391 // Sender Thread: |
| 458 // This thread will be used to call Win32 APIs to send MIDI message at the | 392 // This thread will be used to call Win32 APIs to send MIDI message at the |
| 459 // specified time. We don't want to call MIDI send APIs on Misc. Task Thread | 393 // specified time. We don't want to call MIDI send APIs on Task Thread |
| 460 // because those APIs could be performed synchronously, hence they could block | 394 // because those APIs could be performed synchronously, hence they could block |
| 461 // the caller thread for a while. See the comment in | 395 // the caller thread for a while. See the comment in |
| 462 // SendLongMidiMessageInternal for details. Currently we expect that the | 396 // SendLongMidiMessageInternal for details. Currently we expect that the |
| 463 // blocking time would be less than 1 second. | 397 // blocking time would be less than 1 second. |
| 464 class MidiServiceWinImpl : public MidiServiceWin { | 398 class MidiServiceWinImpl : public MidiServiceWin, |
| 399 public base::SystemMonitor::DevicesChangedObserver { | |
| 465 public: | 400 public: |
| 466 MidiServiceWinImpl() | 401 MidiServiceWinImpl() |
| 467 : delegate_(nullptr), | 402 : delegate_(nullptr), |
| 468 monitor_thread_("Windows MIDI device monitor thread"), | |
| 469 sender_thread_("Windows MIDI sender thread"), | 403 sender_thread_("Windows MIDI sender thread"), |
| 470 task_thread_("Windows MIDI task thread"), | 404 task_thread_("Windows MIDI task thread"), |
| 471 destructor_started(false) {} | 405 destructor_started(false) {} |
| 472 | 406 |
| 473 ~MidiServiceWinImpl() final { | 407 ~MidiServiceWinImpl() final { |
| 408 // Start() and Stop() of the threads, and AddDevicesChangeObserver() and | |
| 409 // RemoveDevicesChangeObserver() should be called on the same thread. | |
| 410 CHECK(thread_checker_.CalledOnValidThread()); | |
| 411 | |
| 412 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
| |
| 474 destructor_started = true; | 413 destructor_started = true; |
| 475 if (monitor_thread_.IsRunning()) { | |
| 476 monitor_thread_.message_loop()->PostTask( | |
| 477 FROM_HERE, | |
| 478 base::Bind(&MidiServiceWinImpl::StopDeviceMonitorOnMonitorThreadSync, | |
| 479 base::Unretained(this))); | |
| 480 } | |
| 481 { | 414 { |
| 482 std::vector<HMIDIIN> input_devices; | 415 std::vector<HMIDIIN> input_devices; |
| 483 { | 416 { |
| 484 base::AutoLock auto_lock(input_ports_lock_); | 417 base::AutoLock auto_lock(input_ports_lock_); |
| 485 for (auto it : input_device_map_) | 418 for (auto it : input_device_map_) |
| 486 input_devices.push_back(it.first); | 419 input_devices.push_back(it.first); |
| 487 } | 420 } |
| 488 { | 421 { |
| 489 for (const auto handle : input_devices) { | 422 for (const auto handle : input_devices) { |
| 490 MMRESULT result = midiInClose(handle); | 423 MMRESULT result = midiInClose(handle); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 513 result = midiOutReset(handle); | 446 result = midiOutReset(handle); |
| 514 DLOG_IF(ERROR, result != MMSYSERR_NOERROR) | 447 DLOG_IF(ERROR, result != MMSYSERR_NOERROR) |
| 515 << "midiOutReset failed: " << GetOutErrorMessage(result); | 448 << "midiOutReset failed: " << GetOutErrorMessage(result); |
| 516 result = midiOutClose(handle); | 449 result = midiOutClose(handle); |
| 517 } | 450 } |
| 518 DLOG_IF(ERROR, result != MMSYSERR_NOERROR) | 451 DLOG_IF(ERROR, result != MMSYSERR_NOERROR) |
| 519 << "midiOutClose failed: " << GetOutErrorMessage(result); | 452 << "midiOutClose failed: " << GetOutErrorMessage(result); |
| 520 } | 453 } |
| 521 } | 454 } |
| 522 } | 455 } |
| 523 monitor_thread_.Stop(); | |
| 524 sender_thread_.Stop(); | 456 sender_thread_.Stop(); |
| 525 task_thread_.Stop(); | 457 task_thread_.Stop(); |
| 526 } | 458 } |
| 527 | 459 |
| 528 // MidiServiceWin overrides: | 460 // MidiServiceWin overrides: |
| 529 void InitializeAsync(MidiServiceWinDelegate* delegate) final { | 461 void InitializeAsync(MidiServiceWinDelegate* delegate) final { |
| 462 // Start() and Stop() of the threads, and AddDevicesChangeObserver() and | |
| 463 // RemoveDevicesChangeObserver() should be called on the same thread. | |
| 464 CHECK(thread_checker_.CalledOnValidThread()); | |
| 465 | |
| 530 delegate_ = delegate; | 466 delegate_ = delegate; |
| 531 sender_thread_.StartWithOptions( | 467 |
| 532 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); | 468 sender_thread_.Start(); |
| 533 task_thread_.StartWithOptions( | 469 task_thread_.Start(); |
| 534 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); | 470 |
| 535 monitor_thread_.StartWithOptions( | 471 // Start monitoring device changes. This should start before the |
| 536 base::Thread::Options(base::MessageLoop::TYPE_UI, 0)); | 472 // following UpdateDeviceList() call not to miss the event happening |
| 537 monitor_thread_.message_loop()->PostTask( | 473 // between the call and the observer registration. |
| 538 FROM_HERE, base::Bind(&MidiServiceWinImpl::InitializeOnMonitorThread, | 474 base::SystemMonitor::Get()->AddDevicesChangedObserver(this); |
| 539 base::Unretained(this))); | 475 |
| 476 UpdateDeviceList(); | |
| 477 | |
| 478 task_thread_.message_loop()->PostTask( | |
| 479 FROM_HERE, | |
| 480 base::Bind(&MidiServiceWinImpl::CompleteInitializationOnTaskThread, | |
| 481 base::Unretained(this), MIDI_OK)); | |
| 540 } | 482 } |
| 541 | 483 |
| 542 void SendMidiDataAsync(uint32 port_number, | 484 void SendMidiDataAsync(uint32 port_number, |
| 543 const std::vector<uint8>& data, | 485 const std::vector<uint8>& data, |
| 544 base::TimeTicks time) final { | 486 base::TimeTicks time) final { |
| 545 if (destructor_started) { | 487 if (destructor_started) { |
| 546 LOG(ERROR) << "ThreadSafeSendData failed because MidiServiceWinImpl is " | 488 LOG(ERROR) << "ThreadSafeSendData failed because MidiServiceWinImpl is " |
| 547 "being destructed. port: " << port_number; | 489 "being destructed. port: " << port_number; |
| 548 return; | 490 return; |
| 549 } | 491 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 567 state->port_age, data, time), | 509 state->port_age, data, time), |
| 568 time - now); | 510 time - now); |
| 569 } else { | 511 } else { |
| 570 sender_thread_.message_loop()->PostTask( | 512 sender_thread_.message_loop()->PostTask( |
| 571 FROM_HERE, base::Bind(&MidiServiceWinImpl::SendOnSenderThread, | 513 FROM_HERE, base::Bind(&MidiServiceWinImpl::SendOnSenderThread, |
| 572 base::Unretained(this), port_number, | 514 base::Unretained(this), port_number, |
| 573 state->port_age, data, time)); | 515 state->port_age, data, time)); |
| 574 } | 516 } |
| 575 } | 517 } |
| 576 | 518 |
| 519 // base::SystemMonitor::DevicesChangedObserver overrides: | |
| 520 void OnDevicesChanged(base::SystemMonitor::DeviceType device_type) final { | |
| 521 CHECK(thread_checker_.CalledOnValidThread()); | |
| 522 switch (device_type) { | |
| 523 case base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE: | |
| 524 case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE: | |
| 525 // Add case of other unrelated device types here. | |
| 526 return; | |
| 527 case base::SystemMonitor::DEVTYPE_UNKNOWN: | |
| 528 // Interested in MIDI devices. Try updating the device list. | |
| 529 UpdateDeviceList(); | |
| 530 break; | |
| 531 // No default here to capture new DeviceType by compile time. | |
| 532 } | |
| 533 } | |
| 534 | |
| 577 private: | 535 private: |
| 578 scoped_refptr<MidiInputDeviceState> GetInputDeviceFromHandle( | 536 scoped_refptr<MidiInputDeviceState> GetInputDeviceFromHandle( |
| 579 HMIDIIN midi_handle) { | 537 HMIDIIN midi_handle) { |
| 580 base::AutoLock auto_lock(input_ports_lock_); | 538 base::AutoLock auto_lock(input_ports_lock_); |
| 581 const auto it = input_device_map_.find(midi_handle); | 539 const auto it = input_device_map_.find(midi_handle); |
| 582 return (it != input_device_map_.end() ? it->second : nullptr); | 540 return (it != input_device_map_.end() ? it->second : nullptr); |
| 583 } | 541 } |
| 584 | 542 |
| 585 scoped_refptr<MidiOutputDeviceState> GetOutputDeviceFromHandle( | 543 scoped_refptr<MidiOutputDeviceState> GetOutputDeviceFromHandle( |
| 586 HMIDIOUT midi_handle) { | 544 HMIDIOUT midi_handle) { |
| 587 base::AutoLock auto_lock(output_ports_lock_); | 545 base::AutoLock auto_lock(output_ports_lock_); |
| 588 const auto it = output_device_map_.find(midi_handle); | 546 const auto it = output_device_map_.find(midi_handle); |
| 589 return (it != output_device_map_.end() ? it->second : nullptr); | 547 return (it != output_device_map_.end() ? it->second : nullptr); |
| 590 } | 548 } |
| 591 | 549 |
| 592 scoped_refptr<MidiOutputDeviceState> GetOutputDeviceFromPort( | 550 scoped_refptr<MidiOutputDeviceState> GetOutputDeviceFromPort( |
| 593 uint32 port_number) { | 551 uint32 port_number) { |
| 594 base::AutoLock auto_lock(output_ports_lock_); | 552 base::AutoLock auto_lock(output_ports_lock_); |
| 595 if (output_ports_.size() <= port_number) | 553 if (output_ports_.size() <= port_number) |
| 596 return nullptr; | 554 return nullptr; |
| 597 return output_ports_[port_number]; | 555 return output_ports_[port_number]; |
| 598 } | 556 } |
| 599 | 557 |
| 558 void UpdateDeviceList() { | |
| 559 task_thread_.message_loop()->PostTask( | |
| 560 FROM_HERE, base::Bind(&MidiServiceWinImpl::UpdateDeviceListOnTaskThread, | |
| 561 base::Unretained(this))); | |
| 562 } | |
| 563 | |
| 600 ///////////////////////////////////////////////////////////////////////////// | 564 ///////////////////////////////////////////////////////////////////////////// |
| 601 // Callbacks on the OS multimedia thread. | 565 // Callbacks on the OS multimedia thread. |
| 602 ///////////////////////////////////////////////////////////////////////////// | 566 ///////////////////////////////////////////////////////////////////////////// |
| 603 | 567 |
| 604 static void CALLBACK OnMidiInEventOnMultimediaThread(HMIDIIN midi_in_handle, | 568 static void CALLBACK |
| 605 UINT message, | 569 OnMidiInEventOnMainlyMultimediaThread(HMIDIIN midi_in_handle, |
| 606 DWORD_PTR instance, | 570 UINT message, |
| 607 DWORD_PTR param1, | 571 DWORD_PTR instance, |
| 608 DWORD_PTR param2) { | 572 DWORD_PTR param1, |
| 573 DWORD_PTR param2) { | |
| 609 MidiServiceWinImpl* self = reinterpret_cast<MidiServiceWinImpl*>(instance); | 574 MidiServiceWinImpl* self = reinterpret_cast<MidiServiceWinImpl*>(instance); |
| 610 if (!self) | 575 if (!self) |
| 611 return; | 576 return; |
| 612 switch (message) { | 577 switch (message) { |
| 613 case MIM_OPEN: | 578 case MIM_OPEN: |
| 614 self->OnMidiInOpenOnMultimediaThread(midi_in_handle); | 579 self->OnMidiInOpen(midi_in_handle); |
| 615 break; | 580 break; |
| 616 case MIM_DATA: | 581 case MIM_DATA: |
| 617 self->OnMidiInDataOnMultimediaThread(midi_in_handle, param1, param2); | 582 self->OnMidiInDataOnMultimediaThread(midi_in_handle, param1, param2); |
| 618 break; | 583 break; |
| 619 case MIM_LONGDATA: | 584 case MIM_LONGDATA: |
| 620 self->OnMidiInLongDataOnMultimediaThread(midi_in_handle, param1, | 585 self->OnMidiInLongDataOnMultimediaThread(midi_in_handle, param1, |
| 621 param2); | 586 param2); |
| 622 break; | 587 break; |
| 623 case MIM_CLOSE: | 588 case MIM_CLOSE: |
| 589 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?
| |
| 624 self->OnMidiInCloseOnMultimediaThread(midi_in_handle); | 590 self->OnMidiInCloseOnMultimediaThread(midi_in_handle); |
| 625 break; | 591 break; |
| 626 } | 592 } |
| 627 } | 593 } |
| 628 | 594 |
| 629 void OnMidiInOpenOnMultimediaThread(HMIDIIN midi_in_handle) { | 595 void OnMidiInOpen(HMIDIIN midi_in_handle) { |
| 630 UINT device_id = 0; | 596 UINT device_id = 0; |
| 631 MMRESULT result = midiInGetID(midi_in_handle, &device_id); | 597 MMRESULT result = midiInGetID(midi_in_handle, &device_id); |
| 632 if (result != MMSYSERR_NOERROR) { | 598 if (result != MMSYSERR_NOERROR) { |
| 633 DLOG(ERROR) << "midiInGetID failed: " << GetInErrorMessage(result); | 599 DLOG(ERROR) << "midiInGetID failed: " << GetInErrorMessage(result); |
| 634 return; | 600 return; |
| 635 } | 601 } |
| 636 MIDIINCAPS2W caps = {}; | 602 MIDIINCAPS2W caps = {}; |
| 637 result = midiInGetDevCaps(device_id, reinterpret_cast<LPMIDIINCAPSW>(&caps), | 603 result = midiInGetDevCaps(device_id, reinterpret_cast<LPMIDIINCAPSW>(&caps), |
| 638 sizeof(caps)); | 604 sizeof(caps)); |
| 639 if (result != MMSYSERR_NOERROR) { | 605 if (result != MMSYSERR_NOERROR) { |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 778 unused_input_ports_[device_info].push(port_number); | 744 unused_input_ports_[device_info].push(port_number); |
| 779 } | 745 } |
| 780 task_thread_.message_loop()->PostTask( | 746 task_thread_.message_loop()->PostTask( |
| 781 FROM_HERE, | 747 FROM_HERE, |
| 782 base::Bind(&MidiServiceWinImpl::SetInputPortStateOnTaskThread, | 748 base::Bind(&MidiServiceWinImpl::SetInputPortStateOnTaskThread, |
| 783 base::Unretained(this), port_number, | 749 base::Unretained(this), port_number, |
| 784 MIDI_PORT_DISCONNECTED)); | 750 MIDI_PORT_DISCONNECTED)); |
| 785 } | 751 } |
| 786 | 752 |
| 787 static void CALLBACK | 753 static void CALLBACK |
| 788 OnMidiOutEventOnMultimediaThread(HMIDIOUT midi_out_handle, | 754 OnMidiOutEventOnMainlyMultimediaThread(HMIDIOUT midi_out_handle, |
| 789 UINT message, | 755 UINT message, |
| 790 DWORD_PTR instance, | 756 DWORD_PTR instance, |
| 791 DWORD_PTR param1, | 757 DWORD_PTR param1, |
| 792 DWORD_PTR param2) { | 758 DWORD_PTR param2) { |
| 793 MidiServiceWinImpl* self = reinterpret_cast<MidiServiceWinImpl*>(instance); | 759 MidiServiceWinImpl* self = reinterpret_cast<MidiServiceWinImpl*>(instance); |
| 794 if (!self) | 760 if (!self) |
| 795 return; | 761 return; |
| 796 switch (message) { | 762 switch (message) { |
| 797 case MOM_OPEN: | 763 case MOM_OPEN: |
| 798 self->OnMidiOutOpenOnMultimediaThread(midi_out_handle, param1, param2); | 764 self->OnMidiOutOpen(midi_out_handle, param1, param2); |
| 799 break; | 765 break; |
| 800 case MOM_DONE: | 766 case MOM_DONE: |
| 801 self->OnMidiOutDoneOnMultimediaThread(midi_out_handle, param1); | 767 self->OnMidiOutDoneOnMultimediaThread(midi_out_handle, param1); |
| 802 break; | 768 break; |
| 803 case MOM_CLOSE: | 769 case MOM_CLOSE: |
| 804 self->OnMidiOutCloseOnMultimediaThread(midi_out_handle); | 770 self->OnMidiOutCloseOnMultimediaThread(midi_out_handle); |
| 805 break; | 771 break; |
| 806 } | 772 } |
| 807 } | 773 } |
| 808 | 774 |
| 809 void OnMidiOutOpenOnMultimediaThread(HMIDIOUT midi_out_handle, | 775 void OnMidiOutOpen(HMIDIOUT midi_out_handle, |
| 810 DWORD_PTR param1, | 776 DWORD_PTR param1, |
| 811 DWORD_PTR param2) { | 777 DWORD_PTR param2) { |
| 812 UINT device_id = 0; | 778 UINT device_id = 0; |
| 813 MMRESULT result = midiOutGetID(midi_out_handle, &device_id); | 779 MMRESULT result = midiOutGetID(midi_out_handle, &device_id); |
| 814 if (result != MMSYSERR_NOERROR) { | 780 if (result != MMSYSERR_NOERROR) { |
| 815 DLOG(ERROR) << "midiOutGetID failed: " << GetOutErrorMessage(result); | 781 DLOG(ERROR) << "midiOutGetID failed: " << GetOutErrorMessage(result); |
| 816 return; | 782 return; |
| 817 } | 783 } |
| 818 MIDIOUTCAPS2W caps = {}; | 784 MIDIOUTCAPS2W caps = {}; |
| 819 result = midiOutGetDevCaps( | 785 result = midiOutGetDevCaps( |
| 820 device_id, reinterpret_cast<LPMIDIOUTCAPSW>(&caps), sizeof(caps)); | 786 device_id, reinterpret_cast<LPMIDIOUTCAPSW>(&caps), sizeof(caps)); |
| 821 if (result != MMSYSERR_NOERROR) { | 787 if (result != MMSYSERR_NOERROR) { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 899 state->closed = true; | 865 state->closed = true; |
| 900 } | 866 } |
| 901 task_thread_.message_loop()->PostTask( | 867 task_thread_.message_loop()->PostTask( |
| 902 FROM_HERE, | 868 FROM_HERE, |
| 903 base::Bind(&MidiServiceWinImpl::SetOutputPortStateOnTaskThread, | 869 base::Bind(&MidiServiceWinImpl::SetOutputPortStateOnTaskThread, |
| 904 base::Unretained(this), port_number, | 870 base::Unretained(this), port_number, |
| 905 MIDI_PORT_DISCONNECTED)); | 871 MIDI_PORT_DISCONNECTED)); |
| 906 } | 872 } |
| 907 | 873 |
| 908 ///////////////////////////////////////////////////////////////////////////// | 874 ///////////////////////////////////////////////////////////////////////////// |
| 909 // Callbacks on the monitor thread. | |
| 910 ///////////////////////////////////////////////////////////////////////////// | |
| 911 | |
| 912 void AssertOnMonitorThread() { | |
| 913 DCHECK_EQ(monitor_thread_.thread_id(), base::PlatformThread::CurrentId()); | |
| 914 } | |
| 915 | |
| 916 void InitializeOnMonitorThread() { | |
| 917 AssertOnMonitorThread(); | |
| 918 // Synchronously open all the existing MIDI devices. | |
| 919 TryOpenAllDevicesOnMonitorThreadSync(); | |
| 920 // Since |TryOpenAllDevicesOnMonitorThreadSync()| is a blocking call, it is | |
| 921 // guaranteed that all the initial MIDI ports are already opened here, and | |
| 922 // corresponding tasks to call |AddInputPortOnTaskThread()| and | |
| 923 // |AddOutputPortOnTaskThread()| are already queued in the Misc. Task | |
| 924 // Thread. This means that the following task to call | |
| 925 // |CompleteInitializationOnTaskThread()| are always called after all the | |
| 926 // pending tasks to call |AddInputPortOnTaskThread()| and | |
| 927 // |AddOutputPortOnTaskThread()| are completed. | |
| 928 task_thread_.message_loop()->PostTask( | |
| 929 FROM_HERE, | |
| 930 base::Bind(&MidiServiceWinImpl::CompleteInitializationOnTaskThread, | |
| 931 base::Unretained(this), MIDI_OK)); | |
| 932 // Start monitoring based on notifications generated by | |
| 933 // RegisterDeviceNotificationW API. | |
| 934 device_monitor_window_.reset(new DeviceMonitorWindow( | |
| 935 base::Bind(&MidiServiceWinImpl::TryOpenAllDevicesOnMonitorThreadSync, | |
| 936 base::Unretained(this)))); | |
| 937 } | |
| 938 | |
| 939 void StopDeviceMonitorOnMonitorThreadSync() { | |
| 940 device_monitor_window_.reset(); | |
| 941 } | |
| 942 | |
| 943 // Note that this is a blocking method. | |
| 944 void TryOpenAllDevicesOnMonitorThreadSync() { | |
| 945 AssertOnMonitorThread(); | |
| 946 const UINT num_in_devices = midiInGetNumDevs(); | |
| 947 for (UINT device_id = 0; device_id < num_in_devices; ++device_id) { | |
| 948 // Here we use |CALLBACK_FUNCTION| to subscribe MIM_DATA, MIM_LONGDATA, | |
| 949 // MIM_OPEN, and MIM_CLOSE events. | |
| 950 // - MIM_DATA: This is the only way to get a short MIDI message with | |
| 951 // timestamp information. | |
| 952 // - MIM_LONGDATA: This is the only way to get a long MIDI message with | |
| 953 // timestamp information. | |
| 954 // - MIM_OPEN: This event is sent the input device is opened. | |
| 955 // - MIM_CLOSE: This event is sent when 1) midiInClose() is called, or 2) | |
| 956 // the MIDI device becomes unavailable for some reasons, e.g., the | |
| 957 // cable is disconnected. As for the former case, HMIDIOUT will be | |
| 958 // invalidated soon after the callback is finished. As for the later | |
| 959 // case, however, HMIDIOUT continues to be valid until midiInClose() | |
| 960 // is called. | |
| 961 HMIDIIN midi_handle = kInvalidMidiInHandle; | |
| 962 const MMRESULT result = midiInOpen( | |
| 963 &midi_handle, device_id, | |
| 964 reinterpret_cast<DWORD_PTR>(&OnMidiInEventOnMultimediaThread), | |
| 965 reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION); | |
| 966 DLOG_IF(ERROR, result != MMSYSERR_NOERROR && result != MMSYSERR_ALLOCATED) | |
| 967 << "Failed to open output device. " | |
| 968 << " id: " << device_id << " message: " << GetInErrorMessage(result); | |
| 969 } | |
| 970 | |
| 971 const UINT num_out_devices = midiOutGetNumDevs(); | |
| 972 for (UINT device_id = 0; device_id < num_out_devices; ++device_id) { | |
| 973 // Here we use |CALLBACK_FUNCTION| to subscribe MOM_DONE, MOM_OPEN, and | |
| 974 // MOM_CLOSE events. | |
| 975 // - MOM_DONE: SendLongMidiMessageInternal() relies on this event to clean | |
| 976 // up the backing store where a long MIDI message is stored. | |
| 977 // - MOM_OPEN: This event is sent the output device is opened. | |
| 978 // - MOM_CLOSE: This event is sent when 1) midiOutClose() is called, or 2) | |
| 979 // the MIDI device becomes unavailable for some reasons, e.g., the | |
| 980 // cable is disconnected. As for the former case, HMIDIOUT will be | |
| 981 // invalidated soon after the callback is finished. As for the later | |
| 982 // case, however, HMIDIOUT continues to be valid until midiOutClose() | |
| 983 // is called. | |
| 984 HMIDIOUT midi_handle = kInvalidMidiOutHandle; | |
| 985 const MMRESULT result = midiOutOpen( | |
| 986 &midi_handle, device_id, | |
| 987 reinterpret_cast<DWORD_PTR>(&OnMidiOutEventOnMultimediaThread), | |
| 988 reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION); | |
| 989 if (result != MMSYSERR_NOERROR && result != MMSYSERR_ALLOCATED) { | |
| 990 DLOG(ERROR) << "Failed to open output device. " | |
| 991 << " id: " << device_id | |
| 992 << " message: " << GetOutErrorMessage(result); | |
| 993 } | |
| 994 } | |
| 995 } | |
| 996 | |
| 997 ///////////////////////////////////////////////////////////////////////////// | |
| 998 // Callbacks on the sender thread. | 875 // Callbacks on the sender thread. |
| 999 ///////////////////////////////////////////////////////////////////////////// | 876 ///////////////////////////////////////////////////////////////////////////// |
| 1000 | 877 |
| 1001 void AssertOnSenderThread() { | 878 void AssertOnSenderThread() { |
| 1002 DCHECK_EQ(sender_thread_.thread_id(), base::PlatformThread::CurrentId()); | 879 DCHECK_EQ(sender_thread_.thread_id(), base::PlatformThread::CurrentId()); |
| 1003 } | 880 } |
| 1004 | 881 |
| 1005 void SendOnSenderThread(uint32 port_number, | 882 void SendOnSenderThread(uint32 port_number, |
| 1006 uint64 port_age, | 883 uint64 port_age, |
| 1007 const std::vector<uint8>& data, | 884 const std::vector<uint8>& data, |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1051 } | 928 } |
| 1052 | 929 |
| 1053 ///////////////////////////////////////////////////////////////////////////// | 930 ///////////////////////////////////////////////////////////////////////////// |
| 1054 // Callbacks on the task thread. | 931 // Callbacks on the task thread. |
| 1055 ///////////////////////////////////////////////////////////////////////////// | 932 ///////////////////////////////////////////////////////////////////////////// |
| 1056 | 933 |
| 1057 void AssertOnTaskThread() { | 934 void AssertOnTaskThread() { |
| 1058 DCHECK_EQ(task_thread_.thread_id(), base::PlatformThread::CurrentId()); | 935 DCHECK_EQ(task_thread_.thread_id(), base::PlatformThread::CurrentId()); |
| 1059 } | 936 } |
| 1060 | 937 |
| 938 void UpdateDeviceListOnTaskThread() { | |
| 939 AssertOnTaskThread(); | |
| 940 const UINT num_in_devices = midiInGetNumDevs(); | |
| 941 for (UINT device_id = 0; device_id < num_in_devices; ++device_id) { | |
| 942 // Here we use |CALLBACK_FUNCTION| to subscribe MIM_DATA, MIM_LONGDATA, | |
| 943 // MIM_OPEN, and MIM_CLOSE events. | |
| 944 // - MIM_DATA: This is the only way to get a short MIDI message with | |
| 945 // timestamp information. | |
| 946 // - MIM_LONGDATA: This is the only way to get a long MIDI message with | |
| 947 // timestamp information. | |
| 948 // - MIM_OPEN: This event is sent the input device is opened. Note that | |
| 949 // this message is called on the caller thread. | |
| 950 // - MIM_CLOSE: This event is sent when 1) midiInClose() is called, or 2) | |
| 951 // the MIDI device becomes unavailable for some reasons, e.g., the | |
| 952 // cable is disconnected. As for the former case, HMIDIOUT will be | |
| 953 // invalidated soon after the callback is finished. As for the later | |
| 954 // case, however, HMIDIOUT continues to be valid until midiInClose() | |
| 955 // is called. | |
| 956 HMIDIIN midi_handle = kInvalidMidiInHandle; | |
| 957 const MMRESULT result = midiInOpen( | |
| 958 &midi_handle, device_id, | |
| 959 reinterpret_cast<DWORD_PTR>(&OnMidiInEventOnMainlyMultimediaThread), | |
| 960 reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION); | |
| 961 DLOG_IF(ERROR, result != MMSYSERR_NOERROR && result != MMSYSERR_ALLOCATED) | |
| 962 << "Failed to open output device. " | |
| 963 << " id: " << device_id << " message: " << GetInErrorMessage(result); | |
| 964 } | |
| 965 | |
| 966 const UINT num_out_devices = midiOutGetNumDevs(); | |
| 967 for (UINT device_id = 0; device_id < num_out_devices; ++device_id) { | |
| 968 // Here we use |CALLBACK_FUNCTION| to subscribe MOM_DONE, MOM_OPEN, and | |
| 969 // MOM_CLOSE events. | |
| 970 // - MOM_DONE: SendLongMidiMessageInternal() relies on this event to clean | |
| 971 // up the backing store where a long MIDI message is stored. | |
| 972 // - MOM_OPEN: This event is sent the output device is opened. Note that | |
| 973 // this message is called on the caller thread. | |
| 974 // - MOM_CLOSE: This event is sent when 1) midiOutClose() is called, or 2) | |
| 975 // the MIDI device becomes unavailable for some reasons, e.g., the | |
| 976 // cable is disconnected. As for the former case, HMIDIOUT will be | |
| 977 // invalidated soon after the callback is finished. As for the later | |
| 978 // case, however, HMIDIOUT continues to be valid until midiOutClose() | |
| 979 // is called. | |
| 980 HMIDIOUT midi_handle = kInvalidMidiOutHandle; | |
| 981 const MMRESULT result = midiOutOpen( | |
| 982 &midi_handle, device_id, | |
| 983 reinterpret_cast<DWORD_PTR>(&OnMidiOutEventOnMainlyMultimediaThread), | |
| 984 reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION); | |
| 985 DLOG_IF(ERROR, result != MMSYSERR_NOERROR && result != MMSYSERR_ALLOCATED) | |
| 986 << "Failed to open output device. " | |
| 987 << " id: " << device_id << " message: " << GetOutErrorMessage(result); | |
| 988 } | |
| 989 } | |
| 990 | |
| 1061 void StartInputDeviceOnTaskThread(HMIDIIN midi_in_handle) { | 991 void StartInputDeviceOnTaskThread(HMIDIIN midi_in_handle) { |
| 1062 AssertOnTaskThread(); | 992 AssertOnTaskThread(); |
| 1063 auto state = GetInputDeviceFromHandle(midi_in_handle); | 993 auto state = GetInputDeviceFromHandle(midi_in_handle); |
| 1064 if (!state) | 994 if (!state) |
| 1065 return; | 995 return; |
| 1066 MMRESULT result = | 996 MMRESULT result = |
| 1067 midiInPrepareHeader(state->midi_handle, state->midi_header.get(), | 997 midiInPrepareHeader(state->midi_handle, state->midi_header.get(), |
| 1068 sizeof(*state->midi_header)); | 998 sizeof(*state->midi_header)); |
| 1069 if (result != MMSYSERR_NOERROR) { | 999 if (result != MMSYSERR_NOERROR) { |
| 1070 DLOG(ERROR) << "Failed to initialize input buffer: " | 1000 DLOG(ERROR) << "Failed to initialize input buffer: " |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1120 delegate_->OnSetOutputPortState(port_index, state); | 1050 delegate_->OnSetOutputPortState(port_index, state); |
| 1121 } | 1051 } |
| 1122 | 1052 |
| 1123 ///////////////////////////////////////////////////////////////////////////// | 1053 ///////////////////////////////////////////////////////////////////////////// |
| 1124 // Fields: | 1054 // Fields: |
| 1125 ///////////////////////////////////////////////////////////////////////////// | 1055 ///////////////////////////////////////////////////////////////////////////// |
| 1126 | 1056 |
| 1127 // Does not take ownership. | 1057 // Does not take ownership. |
| 1128 MidiServiceWinDelegate* delegate_; | 1058 MidiServiceWinDelegate* delegate_; |
| 1129 | 1059 |
| 1130 base::Thread monitor_thread_; | 1060 base::ThreadChecker thread_checker_; |
| 1061 | |
| 1131 base::Thread sender_thread_; | 1062 base::Thread sender_thread_; |
| 1132 base::Thread task_thread_; | 1063 base::Thread task_thread_; |
| 1133 | 1064 |
| 1134 scoped_ptr<DeviceMonitorWindow> device_monitor_window_; | |
| 1135 | |
| 1136 base::Lock input_ports_lock_; | 1065 base::Lock input_ports_lock_; |
| 1137 base::hash_map<HMIDIIN, scoped_refptr<MidiInputDeviceState>> | 1066 base::hash_map<HMIDIIN, scoped_refptr<MidiInputDeviceState>> |
| 1138 input_device_map_; // GUARDED_BY(input_ports_lock_) | 1067 input_device_map_; // GUARDED_BY(input_ports_lock_) |
| 1139 PortNumberCache unused_input_ports_; // GUARDED_BY(input_ports_lock_) | 1068 PortNumberCache unused_input_ports_; // GUARDED_BY(input_ports_lock_) |
| 1140 std::vector<scoped_refptr<MidiInputDeviceState>> | 1069 std::vector<scoped_refptr<MidiInputDeviceState>> |
| 1141 input_ports_; // GUARDED_BY(input_ports_lock_) | 1070 input_ports_; // GUARDED_BY(input_ports_lock_) |
| 1142 std::vector<uint64> input_ports_ages_; // GUARDED_BY(input_ports_lock_) | 1071 std::vector<uint64> input_ports_ages_; // GUARDED_BY(input_ports_lock_) |
| 1143 | 1072 |
| 1144 base::Lock output_ports_lock_; | 1073 base::Lock output_ports_lock_; |
| 1145 base::hash_map<HMIDIOUT, scoped_refptr<MidiOutputDeviceState>> | 1074 base::hash_map<HMIDIOUT, scoped_refptr<MidiOutputDeviceState>> |
| 1146 output_device_map_; // GUARDED_BY(output_ports_lock_) | 1075 output_device_map_; // GUARDED_BY(output_ports_lock_) |
| 1147 PortNumberCache unused_output_ports_; // GUARDED_BY(output_ports_lock_) | 1076 PortNumberCache unused_output_ports_; // GUARDED_BY(output_ports_lock_) |
| 1148 std::vector<scoped_refptr<MidiOutputDeviceState>> | 1077 std::vector<scoped_refptr<MidiOutputDeviceState>> |
| 1149 output_ports_; // GUARDED_BY(output_ports_lock_) | 1078 output_ports_; // GUARDED_BY(output_ports_lock_) |
| 1150 std::vector<uint64> output_ports_ages_; // GUARDED_BY(output_ports_lock_) | 1079 std::vector<uint64> output_ports_ages_; // GUARDED_BY(output_ports_lock_) |
| 1151 | 1080 |
| 1152 // True if one thread reached MidiServiceWinImpl::~MidiServiceWinImpl(). Note | 1081 // True if one thread reached MidiServiceWinImpl::~MidiServiceWinImpl(). Note |
| 1153 // that MidiServiceWinImpl::~MidiServiceWinImpl() is blocked until | 1082 // that MidiServiceWinImpl::~MidiServiceWinImpl() is blocked until |
| 1154 // |monitor_thread_|, |sender_thread_|, and |task_thread_| are stopped. | 1083 // |sender_thread_|, and |task_thread_| are stopped. |
| 1155 // This flag can be used as the signal that when background tasks must be | 1084 // This flag can be used as the signal that when background tasks must be |
| 1156 // interrupted. | 1085 // interrupted. |
| 1157 // TODO(toyoshim): Use std::atomic<bool> when it is allowed. | 1086 // TODO(toyoshim): Use std::atomic<bool> when it is allowed. |
| 1158 volatile bool destructor_started; | 1087 volatile bool destructor_started; |
| 1159 | 1088 |
| 1160 DISALLOW_COPY_AND_ASSIGN(MidiServiceWinImpl); | 1089 DISALLOW_COPY_AND_ASSIGN(MidiServiceWinImpl); |
| 1161 }; | 1090 }; |
| 1162 | 1091 |
| 1163 } // namespace | 1092 } // namespace |
| 1164 | 1093 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1186 // TOOD(toyoshim): This calculation should be done when the date is actually | 1115 // TOOD(toyoshim): This calculation should be done when the date is actually |
| 1187 // sent. | 1116 // sent. |
| 1188 client->AccumulateMidiBytesSent(data.size()); | 1117 client->AccumulateMidiBytesSent(data.size()); |
| 1189 } | 1118 } |
| 1190 | 1119 |
| 1191 MidiManager* MidiManager::Create() { | 1120 MidiManager* MidiManager::Create() { |
| 1192 return new MidiManagerWin(); | 1121 return new MidiManagerWin(); |
| 1193 } | 1122 } |
| 1194 | 1123 |
| 1195 } // namespace media | 1124 } // namespace media |
| OLD | NEW |