Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/dynamically_initialized_midi_manager_win.h" | 5 #include "media/midi/dynamically_initialized_midi_manager_win.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 | 8 |
| 9 #include <mmreg.h> | 9 #include <mmreg.h> |
| 10 #include <mmsystem.h> | 10 #include <mmsystem.h> |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 // Calculates event time from elapsed time that system provides. | 32 // Calculates event time from elapsed time that system provides. |
| 33 base::TimeTicks CalculateInEventTime(size_t index, uint32_t elapsed_ms) const; | 33 base::TimeTicks CalculateInEventTime(size_t index, uint32_t elapsed_ms) const; |
| 34 | 34 |
| 35 // Registers HMIDIIN handle to resolve port index. | 35 // Registers HMIDIIN handle to resolve port index. |
| 36 void RegisterInHandle(HMIDIIN handle, size_t index); | 36 void RegisterInHandle(HMIDIIN handle, size_t index); |
| 37 | 37 |
| 38 // Unregisters HMIDIIN handle. | 38 // Unregisters HMIDIIN handle. |
| 39 void UnregisterInHandle(HMIDIIN handle); | 39 void UnregisterInHandle(HMIDIIN handle); |
| 40 | 40 |
| 41 // Finds HMIDIIN handle and fullfil |out_index| with the port index. | 41 // Finds HMIDIIN handle and fullfil |out_index| with the port index. |
| 42 bool FindHandle(HMIDIIN hmi, size_t* out_index); | 42 bool FindInHandle(HMIDIIN hmi, size_t* out_index); |
| 43 | 43 |
| 44 // Restores used input buffer for the next data receive. | 44 // Restores used input buffer for the next data receive. |
| 45 void RestoreInBuffer(size_t index); | 45 void RestoreInBuffer(size_t index); |
| 46 | 46 |
| 47 // Ports accessors. | 47 // Ports accessors. |
| 48 std::vector<std::unique_ptr<InPort>>* inputs() { return &input_ports_; } | 48 std::vector<std::unique_ptr<InPort>>* inputs() { return &input_ports_; } |
| 49 std::vector<std::unique_ptr<OutPort>>* outputs() { return &output_ports_; } | 49 std::vector<std::unique_ptr<OutPort>>* outputs() { return &output_ports_; } |
| 50 | 50 |
| 51 // Handles MIDI input port callbacks that runs on a system provided thread. | 51 // Handles MIDI input port callbacks that runs on a system provided thread. |
| 52 static void CALLBACK HandleMidiInCallback(HMIDIIN hmi, | 52 static void CALLBACK HandleMidiInCallback(HMIDIIN hmi, |
| 53 UINT msg, | 53 UINT msg, |
| 54 DWORD_PTR instance, | 54 DWORD_PTR instance, |
| 55 DWORD_PTR param1, | 55 DWORD_PTR param1, |
| 56 DWORD_PTR param2); | 56 DWORD_PTR param2); |
| 57 | 57 |
| 58 // Handles MIDI output port callbacks that runs on a system provided thread. | |
| 59 static void CALLBACK HandleMidiOutCallback(HMIDIOUT hmo, | |
| 60 UINT msg, | |
| 61 DWORD_PTR instance, | |
| 62 DWORD_PTR param1, | |
| 63 DWORD_PTR param2); | |
| 64 | |
| 58 private: | 65 private: |
| 59 // Holds all MIDI input or output ports connected once. | 66 // Holds all MIDI input or output ports connected once. |
| 60 std::vector<std::unique_ptr<InPort>> input_ports_; | 67 std::vector<std::unique_ptr<InPort>> input_ports_; |
| 61 std::vector<std::unique_ptr<OutPort>> output_ports_; | 68 std::vector<std::unique_ptr<OutPort>> output_ports_; |
| 62 | 69 |
| 63 // Map to resolve MIDI input port index from HMIDIIN. | 70 // Map to resolve MIDI input port index from HMIDIIN. |
| 64 std::map<HMIDIIN, size_t> hmidiin_to_index_map_; | 71 std::map<HMIDIIN, size_t> hmidiin_to_index_map_; |
| 65 }; | 72 }; |
| 66 | 73 |
| 67 namespace { | 74 namespace { |
| 68 | 75 |
| 69 // Assumes that nullptr represents an invalid MIDI handle. | 76 // Assumes that nullptr represents an invalid MIDI handle. |
| 70 constexpr HMIDIIN kInvalidInHandle = nullptr; | 77 constexpr HMIDIIN kInvalidInHandle = nullptr; |
| 71 constexpr HMIDIOUT kInvalidOutHandle = nullptr; | 78 constexpr HMIDIOUT kInvalidOutHandle = nullptr; |
| 72 | 79 |
| 80 // Defines SysEx message size limit. | |
| 81 // TODO(crbug.com/383578): This restriction should be removed once Web MIDI | |
| 82 // defines a standardized way to handle large sysex messages. | |
| 83 // Note for built-in USB-MIDI driver: | |
| 84 // From an observation on Windows 7/8.1 with a USB-MIDI keyboard, | |
| 85 // midiOutLongMsg() will be always blocked. Sending 64 bytes or less data takes | |
| 86 // roughly 300 usecs. Sending 2048 bytes or more data takes roughly | |
| 87 // |message.size() / (75 * 1024)| secs in practice. Here we put 256 KB size | |
| 88 // limit on SysEx message, with hoping that midiOutLongMsg will be blocked at | |
| 89 // most 4 sec or so with a typical USB-MIDI device. | |
| 90 // TODO(toyoshim): Consider to use linked small buffers so that midiOutReset() | |
| 91 // can abort sending unhandled following buffers. | |
| 92 constexpr size_t kSysExSizeLimit = 256 * 1024; | |
| 93 | |
| 73 // Defines input buffer size. | 94 // Defines input buffer size. |
| 74 constexpr size_t kBufferLength = 32 * 1024; | 95 constexpr size_t kBufferLength = 32 * 1024; |
| 75 | 96 |
| 76 // Global variables to identify MidiManager instance. | 97 // Global variables to identify MidiManager instance. |
| 77 constexpr int kInvalidInstanceId = -1; | 98 constexpr int kInvalidInstanceId = -1; |
| 78 int g_active_instance_id = kInvalidInstanceId; | 99 int g_active_instance_id = kInvalidInstanceId; |
| 79 DynamicallyInitializedMidiManagerWin* g_manager_instance = nullptr; | 100 DynamicallyInitializedMidiManagerWin* g_manager_instance = nullptr; |
| 80 | 101 |
| 81 // Obtains base::Lock instance pointer to lock instance_id. | 102 // Obtains base::Lock instance pointer to lock instance_id. |
| 82 base::Lock* GetInstanceIdLock() { | 103 base::Lock* GetInstanceIdLock() { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 midiInReset(handle); | 175 midiInReset(handle); |
| 155 | 176 |
| 156 // Obtains MIDIHDR ownership to release allocated buffers. | 177 // Obtains MIDIHDR ownership to release allocated buffers. |
| 157 ScopedMIDIHDR hdr(lphdr); | 178 ScopedMIDIHDR hdr(lphdr); |
| 158 if (hdr) | 179 if (hdr) |
| 159 midiInUnprepareHeader(handle, hdr.get(), sizeof(*hdr)); | 180 midiInUnprepareHeader(handle, hdr.get(), sizeof(*hdr)); |
| 160 midiInClose(handle); | 181 midiInClose(handle); |
| 161 } | 182 } |
| 162 | 183 |
| 163 void FinalizeOutPort(HMIDIOUT handle) { | 184 void FinalizeOutPort(HMIDIOUT handle) { |
| 185 // Resets inflight buffers. This will cancel sending data that system | |
| 186 // holds and were not sent yet. | |
| 187 midiOutReset(handle); | |
| 164 midiOutClose(handle); | 188 midiOutClose(handle); |
| 165 } | 189 } |
| 166 | 190 |
| 167 // Handles MIDI output port callbacks that runs on a system provided thread. | |
| 168 void CALLBACK HandleMidiOutCallback(HMIDIOUT hmo, | |
| 169 UINT msg, | |
| 170 DWORD_PTR instance, | |
| 171 DWORD_PTR param1, | |
| 172 DWORD_PTR param2) { | |
| 173 // TODO(toyoshim): Following patches will implement actual functions. | |
| 174 } | |
| 175 | |
| 176 // All instances of Port subclasses are always accessed behind a lock of | 191 // All instances of Port subclasses are always accessed behind a lock of |
| 177 // *GetTaskLock(). Port and subclasses implementation do not need to | 192 // *GetTaskLock(). Port and subclasses implementation do not need to |
| 178 // consider thread safety. | 193 // consider thread safety. |
| 179 class Port { | 194 class Port { |
| 180 public: | 195 public: |
| 181 Port(const std::string& type, | 196 Port(const std::string& type, |
| 182 uint32_t device_id, | 197 uint32_t device_id, |
| 183 uint16_t manufacturer_id, | 198 uint16_t manufacturer_id, |
| 184 uint16_t product_id, | 199 uint16_t product_id, |
| 185 uint32_t driver_version, | 200 uint32_t driver_version, |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 252 uint32_t device_id_; | 267 uint32_t device_id_; |
| 253 const uint16_t manufacturer_id_; | 268 const uint16_t manufacturer_id_; |
| 254 const uint16_t product_id_; | 269 const uint16_t product_id_; |
| 255 const uint32_t driver_version_; | 270 const uint32_t driver_version_; |
| 256 const std::string product_name_; | 271 const std::string product_name_; |
| 257 MidiPortInfo info_; | 272 MidiPortInfo info_; |
| 258 }; // class Port | 273 }; // class Port |
| 259 | 274 |
| 260 } // namespace | 275 } // namespace |
| 261 | 276 |
| 262 // TODO(toyoshim): Following patches will implement actual functions. | |
| 263 class DynamicallyInitializedMidiManagerWin::InPort final : public Port { | 277 class DynamicallyInitializedMidiManagerWin::InPort final : public Port { |
| 264 public: | 278 public: |
| 265 InPort(DynamicallyInitializedMidiManagerWin* manager, | 279 InPort(DynamicallyInitializedMidiManagerWin* manager, |
| 266 int instance_id, | 280 int instance_id, |
| 267 UINT device_id, | 281 UINT device_id, |
| 268 const MIDIINCAPS2W& caps) | 282 const MIDIINCAPS2W& caps) |
| 269 : Port("input", | 283 : Port("input", |
| 270 device_id, | 284 device_id, |
| 271 caps.wMid, | 285 caps.wMid, |
| 272 caps.wPid, | 286 caps.wPid, |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 370 } | 384 } |
| 371 | 385 |
| 372 private: | 386 private: |
| 373 DynamicallyInitializedMidiManagerWin* manager_; | 387 DynamicallyInitializedMidiManagerWin* manager_; |
| 374 HMIDIIN in_handle_; | 388 HMIDIIN in_handle_; |
| 375 ScopedMIDIHDR hdr_; | 389 ScopedMIDIHDR hdr_; |
| 376 base::TimeTicks start_time_; | 390 base::TimeTicks start_time_; |
| 377 int instance_id_; | 391 int instance_id_; |
| 378 }; | 392 }; |
| 379 | 393 |
| 380 // TODO(toyoshim): Following patches will implement actual functions. | |
| 381 class DynamicallyInitializedMidiManagerWin::OutPort final : public Port { | 394 class DynamicallyInitializedMidiManagerWin::OutPort final : public Port { |
| 382 public: | 395 public: |
| 383 OutPort(UINT device_id, const MIDIOUTCAPS2W& caps) | 396 OutPort(UINT device_id, const MIDIOUTCAPS2W& caps) |
| 384 : Port("output", | 397 : Port("output", |
| 385 device_id, | 398 device_id, |
| 386 caps.wMid, | 399 caps.wMid, |
| 387 caps.wPid, | 400 caps.wPid, |
| 388 caps.vDriverVersion, | 401 caps.vDriverVersion, |
| 389 base::WideToUTF8( | 402 base::WideToUTF8( |
| 390 base::string16(caps.szPname, wcslen(caps.szPname)))), | 403 base::string16(caps.szPname, wcslen(caps.szPname)))), |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 419 base::Bind(&DynamicallyInitializedMidiManagerWin::SetOutputPortState, | 432 base::Bind(&DynamicallyInitializedMidiManagerWin::SetOutputPortState, |
| 420 base::Unretained(manager), index_, info_.state)); | 433 base::Unretained(manager), index_, info_.state)); |
| 421 } | 434 } |
| 422 | 435 |
| 423 void NotifyPortAdded(DynamicallyInitializedMidiManagerWin* manager) { | 436 void NotifyPortAdded(DynamicallyInitializedMidiManagerWin* manager) { |
| 424 manager->PostReplyTask( | 437 manager->PostReplyTask( |
| 425 base::Bind(&DynamicallyInitializedMidiManagerWin::AddOutputPort, | 438 base::Bind(&DynamicallyInitializedMidiManagerWin::AddOutputPort, |
| 426 base::Unretained(manager), info_)); | 439 base::Unretained(manager), info_)); |
| 427 } | 440 } |
| 428 | 441 |
| 442 void Send(const std::vector<uint8_t>& data) { | |
| 443 if (out_handle_ == kInvalidOutHandle) | |
| 444 return; | |
| 445 | |
| 446 if (data.size() <= 3) { | |
| 447 DWORD message = 0; | |
|
yhirano
2017/03/01 01:48:49
[optional] I would prefer defining |message| as a
Takashi Toyoshima
2017/03/01 03:38:02
changed to uint32_t.
cast is not needed to pass it
| |
| 448 for (size_t i = 0; i < data.size(); ++i) | |
| 449 message |= (static_cast<uint32_t>(data[i]) << (i * 8)); | |
| 450 midiOutShortMsg(out_handle_, message); | |
| 451 } else { | |
| 452 if (data.size() > kSysExSizeLimit) { | |
| 453 LOG(ERROR) << "Ignoring SysEx message due to the size limit" | |
| 454 << ", size = " << data.size(); | |
| 455 // TODO(toyoshim): Consider to report metrics here. | |
| 456 return; | |
| 457 } | |
| 458 ScopedMIDIHDR hdr(CreateMIDIHDR(data)); | |
| 459 MMRESULT result = | |
| 460 midiOutPrepareHeader(out_handle_, hdr.get(), sizeof(*hdr)); | |
| 461 if (result != MMSYSERR_NOERROR) | |
| 462 return; | |
| 463 result = midiOutLongMsg(out_handle_, hdr.get(), sizeof(*hdr)); | |
| 464 if (result != MMSYSERR_NOERROR) | |
| 465 midiOutUnprepareHeader(out_handle_, hdr.get(), sizeof(*hdr)); | |
| 466 else | |
| 467 ignore_result(hdr.release()); | |
| 468 // MIDIHDR will be released on MOM_DONE. | |
| 469 } | |
| 470 } | |
| 471 | |
| 429 // Port overrides: | 472 // Port overrides: |
| 430 bool Connect() override { | 473 bool Connect() override { |
| 431 // Until |software| option is supported, disable Microsoft GS Wavetable | 474 // Until |software| option is supported, disable Microsoft GS Wavetable |
| 432 // Synth that has a known security issue. | 475 // Synth that has a known security issue. |
| 433 if (software_ && manufacturer_id_ == MM_MICROSOFT && | 476 if (software_ && manufacturer_id_ == MM_MICROSOFT && |
| 434 (product_id_ == MM_MSFT_WDMAUDIO_MIDIOUT || | 477 (product_id_ == MM_MSFT_WDMAUDIO_MIDIOUT || |
| 435 product_id_ == MM_MSFT_GENERIC_MIDISYNTH)) { | 478 product_id_ == MM_MSFT_GENERIC_MIDISYNTH)) { |
| 436 return false; | 479 return false; |
| 437 } | 480 } |
| 438 return Port::Connect(); | 481 return Port::Connect(); |
| 439 } | 482 } |
| 440 | 483 |
| 441 bool Disconnect() override { | 484 bool Disconnect() override { |
| 442 if (out_handle_ != kInvalidOutHandle) { | 485 if (out_handle_ != kInvalidOutHandle) { |
| 443 // Following API call may fail because device was already disconnected. | 486 // Following API call may fail because device was already disconnected. |
| 444 // But just in case. | 487 // But just in case. |
| 445 midiOutClose(out_handle_); | 488 midiOutClose(out_handle_); |
| 446 out_handle_ = kInvalidOutHandle; | 489 out_handle_ = kInvalidOutHandle; |
| 447 } | 490 } |
| 448 return Port::Disconnect(); | 491 return Port::Disconnect(); |
| 449 } | 492 } |
| 450 | 493 |
| 451 void Open() override { | 494 void Open() override { |
| 452 MMRESULT result = | 495 MMRESULT result = midiOutOpen( |
| 453 midiOutOpen(&out_handle_, device_id_, | 496 &out_handle_, device_id_, |
| 454 reinterpret_cast<DWORD_PTR>(&HandleMidiOutCallback), 0, | 497 reinterpret_cast<DWORD_PTR>(&PortManager::HandleMidiOutCallback), 0, |
| 455 CALLBACK_FUNCTION); | 498 CALLBACK_FUNCTION); |
| 456 if (result == MMSYSERR_NOERROR) { | 499 if (result == MMSYSERR_NOERROR) { |
| 457 Port::Open(); | 500 Port::Open(); |
| 458 } else { | 501 } else { |
| 459 out_handle_ = kInvalidOutHandle; | 502 out_handle_ = kInvalidOutHandle; |
| 460 Disconnect(); | 503 Disconnect(); |
| 461 } | 504 } |
| 462 } | 505 } |
| 463 | 506 |
| 464 const bool software_; | 507 const bool software_; |
| 465 HMIDIOUT out_handle_; | 508 HMIDIOUT out_handle_; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 480 GetTaskLock()->AssertAcquired(); | 523 GetTaskLock()->AssertAcquired(); |
| 481 hmidiin_to_index_map_[handle] = index; | 524 hmidiin_to_index_map_[handle] = index; |
| 482 } | 525 } |
| 483 | 526 |
| 484 void DynamicallyInitializedMidiManagerWin::PortManager::UnregisterInHandle( | 527 void DynamicallyInitializedMidiManagerWin::PortManager::UnregisterInHandle( |
| 485 HMIDIIN handle) { | 528 HMIDIIN handle) { |
| 486 GetTaskLock()->AssertAcquired(); | 529 GetTaskLock()->AssertAcquired(); |
| 487 hmidiin_to_index_map_.erase(handle); | 530 hmidiin_to_index_map_.erase(handle); |
| 488 } | 531 } |
| 489 | 532 |
| 490 bool DynamicallyInitializedMidiManagerWin::PortManager::FindHandle( | 533 bool DynamicallyInitializedMidiManagerWin::PortManager::FindInHandle( |
| 491 HMIDIIN hmi, | 534 HMIDIIN hmi, |
| 492 size_t* out_index) { | 535 size_t* out_index) { |
| 493 GetTaskLock()->AssertAcquired(); | 536 GetTaskLock()->AssertAcquired(); |
| 494 auto found = hmidiin_to_index_map_.find(hmi); | 537 auto found = hmidiin_to_index_map_.find(hmi); |
| 495 if (found == hmidiin_to_index_map_.end()) | 538 if (found == hmidiin_to_index_map_.end()) |
| 496 return false; | 539 return false; |
| 497 *out_index = found->second; | 540 *out_index = found->second; |
| 498 return true; | 541 return true; |
| 499 } | 542 } |
| 500 | 543 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 521 // and to access member variables that are used on TaskRunner. | 564 // and to access member variables that are used on TaskRunner. |
| 522 base::AutoLock task_lock(*GetTaskLock()); | 565 base::AutoLock task_lock(*GetTaskLock()); |
| 523 { | 566 { |
| 524 base::AutoLock lock(*GetInstanceIdLock()); | 567 base::AutoLock lock(*GetInstanceIdLock()); |
| 525 if (instance_id != g_active_instance_id) | 568 if (instance_id != g_active_instance_id) |
| 526 return; | 569 return; |
| 527 manager = g_manager_instance; | 570 manager = g_manager_instance; |
| 528 } | 571 } |
| 529 | 572 |
| 530 size_t index; | 573 size_t index; |
| 531 if (!manager->port_manager()->FindHandle(hmi, &index)) | 574 if (!manager->port_manager()->FindInHandle(hmi, &index)) |
| 532 return; | 575 return; |
| 533 | 576 |
| 534 DCHECK(msg == MIM_DATA || msg == MIM_LONGDATA); | 577 DCHECK(msg == MIM_DATA || msg == MIM_LONGDATA); |
| 535 if (msg == MIM_DATA) { | 578 if (msg == MIM_DATA) { |
| 536 const uint8_t status_byte = static_cast<uint8_t>(param1 & 0xff); | 579 const uint8_t status_byte = static_cast<uint8_t>(param1 & 0xff); |
| 537 const uint8_t first_data_byte = static_cast<uint8_t>((param1 >> 8) & 0xff); | 580 const uint8_t first_data_byte = static_cast<uint8_t>((param1 >> 8) & 0xff); |
| 538 const uint8_t second_data_byte = | 581 const uint8_t second_data_byte = |
| 539 static_cast<uint8_t>((param1 >> 16) & 0xff); | 582 static_cast<uint8_t>((param1 >> 16) & 0xff); |
| 540 const size_t len = GetMessageLength(status_byte); | 583 const size_t len = GetMessageLength(status_byte); |
| 541 const uint8_t kData[] = {status_byte, first_data_byte, second_data_byte}; | 584 const uint8_t kData[] = {status_byte, first_data_byte, second_data_byte}; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 556 &DynamicallyInitializedMidiManagerWin::ReceiveMidiData, | 599 &DynamicallyInitializedMidiManagerWin::ReceiveMidiData, |
| 557 base::Unretained(manager), index, data, | 600 base::Unretained(manager), index, data, |
| 558 manager->port_manager()->CalculateInEventTime(index, param2))); | 601 manager->port_manager()->CalculateInEventTime(index, param2))); |
| 559 } | 602 } |
| 560 manager->PostTask(base::Bind( | 603 manager->PostTask(base::Bind( |
| 561 &DynamicallyInitializedMidiManagerWin::PortManager::RestoreInBuffer, | 604 &DynamicallyInitializedMidiManagerWin::PortManager::RestoreInBuffer, |
| 562 base::Unretained(manager->port_manager()), index)); | 605 base::Unretained(manager->port_manager()), index)); |
| 563 } | 606 } |
| 564 } | 607 } |
| 565 | 608 |
| 609 void CALLBACK | |
| 610 DynamicallyInitializedMidiManagerWin::PortManager::HandleMidiOutCallback( | |
| 611 HMIDIOUT hmo, | |
| 612 UINT msg, | |
| 613 DWORD_PTR instance, | |
| 614 DWORD_PTR param1, | |
| 615 DWORD_PTR param2) { | |
| 616 if (msg == MOM_DONE) { | |
| 617 ScopedMIDIHDR hdr(reinterpret_cast<LPMIDIHDR>(param1)); | |
| 618 if (!hdr) | |
| 619 return; | |
| 620 // TODO(toyoshim): Call midiOutUnprepareHeader outside the callback. | |
| 621 // Since this callback may be invoked after the manager is destructed, | |
| 622 // and can not send a task to the TaskRunner in such case, we need to | |
| 623 // consider to track MIDIHDR per port, and clean it in port finalization | |
| 624 // steps, too. | |
| 625 midiOutUnprepareHeader(hmo, hdr.get(), sizeof(*hdr)); | |
| 626 } | |
| 627 } | |
| 628 | |
| 566 DynamicallyInitializedMidiManagerWin::DynamicallyInitializedMidiManagerWin( | 629 DynamicallyInitializedMidiManagerWin::DynamicallyInitializedMidiManagerWin( |
| 567 MidiService* service) | 630 MidiService* service) |
| 568 : MidiManager(service), | 631 : MidiManager(service), |
| 569 instance_id_(IssueNextInstanceId()), | 632 instance_id_(IssueNextInstanceId()), |
| 570 port_manager_(base::MakeUnique<PortManager>()) { | 633 port_manager_(base::MakeUnique<PortManager>()) { |
| 571 base::AutoLock lock(*GetInstanceIdLock()); | 634 base::AutoLock lock(*GetInstanceIdLock()); |
| 572 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); | 635 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); |
| 573 | 636 |
| 574 // Obtains the task runner for the current thread that hosts this instnace. | 637 // Obtains the task runner for the current thread that hosts this instnace. |
| 575 thread_runner_ = base::ThreadTaskRunnerHandle::Get(); | 638 thread_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 626 port->Finalize(service()->GetTaskRunner(kTaskRunner)); | 689 port->Finalize(service()->GetTaskRunner(kTaskRunner)); |
| 627 for (const auto& port : *port_manager_->outputs()) | 690 for (const auto& port : *port_manager_->outputs()) |
| 628 port->Finalize(service()->GetTaskRunner(kTaskRunner)); | 691 port->Finalize(service()->GetTaskRunner(kTaskRunner)); |
| 629 } | 692 } |
| 630 | 693 |
| 631 void DynamicallyInitializedMidiManagerWin::DispatchSendMidiData( | 694 void DynamicallyInitializedMidiManagerWin::DispatchSendMidiData( |
| 632 MidiManagerClient* client, | 695 MidiManagerClient* client, |
| 633 uint32_t port_index, | 696 uint32_t port_index, |
| 634 const std::vector<uint8_t>& data, | 697 const std::vector<uint8_t>& data, |
| 635 double timestamp) { | 698 double timestamp) { |
| 636 // TODO(toyoshim): Following patches will implement. | 699 if (timestamp != 0.0) { |
| 700 base::TimeTicks time = base::TimeTicks() + | |
| 701 base::TimeDelta::FromMicroseconds( | |
| 702 timestamp * base::Time::kMicrosecondsPerSecond); | |
| 703 base::TimeTicks now = base::TimeTicks::Now(); | |
| 704 if (now < time) { | |
| 705 PostDelayedTask( | |
| 706 base::Bind(&DynamicallyInitializedMidiManagerWin::SendOnTaskRunner, | |
| 707 base::Unretained(this), client, port_index, data), | |
| 708 time - now); | |
| 709 return; | |
| 710 } | |
| 711 } | |
| 712 PostTask(base::Bind(&DynamicallyInitializedMidiManagerWin::SendOnTaskRunner, | |
| 713 base::Unretained(this), client, port_index, data)); | |
| 637 } | 714 } |
| 638 | 715 |
| 639 void DynamicallyInitializedMidiManagerWin::OnDevicesChanged( | 716 void DynamicallyInitializedMidiManagerWin::OnDevicesChanged( |
| 640 base::SystemMonitor::DeviceType device_type) { | 717 base::SystemMonitor::DeviceType device_type) { |
| 641 // Notified on the I/O thread. | 718 // Notified on the I/O thread. |
| 642 CHECK(thread_runner_->BelongsToCurrentThread()); | 719 CHECK(thread_runner_->BelongsToCurrentThread()); |
| 643 | 720 |
| 644 switch (device_type) { | 721 switch (device_type) { |
| 645 case base::SystemMonitor::DEVTYPE_AUDIO: | 722 case base::SystemMonitor::DEVTYPE_AUDIO: |
| 646 case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE: | 723 case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE: |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 666 service() | 743 service() |
| 667 ->GetTaskRunner(kTaskRunner) | 744 ->GetTaskRunner(kTaskRunner) |
| 668 ->PostTask(FROM_HERE, base::Bind(&RunTask, instance_id_, task)); | 745 ->PostTask(FROM_HERE, base::Bind(&RunTask, instance_id_, task)); |
| 669 } | 746 } |
| 670 | 747 |
| 671 void DynamicallyInitializedMidiManagerWin::PostReplyTask( | 748 void DynamicallyInitializedMidiManagerWin::PostReplyTask( |
| 672 const base::Closure& task) { | 749 const base::Closure& task) { |
| 673 thread_runner_->PostTask(FROM_HERE, base::Bind(&RunTask, instance_id_, task)); | 750 thread_runner_->PostTask(FROM_HERE, base::Bind(&RunTask, instance_id_, task)); |
| 674 } | 751 } |
| 675 | 752 |
| 753 void DynamicallyInitializedMidiManagerWin::PostDelayedTask( | |
| 754 const base::Closure& task, | |
| 755 base::TimeDelta delay) { | |
| 756 service() | |
| 757 ->GetTaskRunner(kTaskRunner) | |
| 758 ->PostDelayedTask(FROM_HERE, base::Bind(&RunTask, instance_id_, task), | |
| 759 delay); | |
| 760 } | |
| 761 | |
| 676 void DynamicallyInitializedMidiManagerWin::InitializeOnTaskRunner() { | 762 void DynamicallyInitializedMidiManagerWin::InitializeOnTaskRunner() { |
| 677 UpdateDeviceListOnTaskRunner(); | 763 UpdateDeviceListOnTaskRunner(); |
| 678 PostReplyTask( | 764 PostReplyTask( |
| 679 base::Bind(&DynamicallyInitializedMidiManagerWin::CompleteInitialization, | 765 base::Bind(&DynamicallyInitializedMidiManagerWin::CompleteInitialization, |
| 680 base::Unretained(this), mojom::Result::OK)); | 766 base::Unretained(this), mojom::Result::OK)); |
| 681 } | 767 } |
| 682 | 768 |
| 683 void DynamicallyInitializedMidiManagerWin::UpdateDeviceListOnTaskRunner() { | 769 void DynamicallyInitializedMidiManagerWin::UpdateDeviceListOnTaskRunner() { |
| 684 std::vector<std::unique_ptr<InPort>> active_input_ports = | 770 std::vector<std::unique_ptr<InPort>> active_input_ports = |
| 685 InPort::EnumerateActivePorts(this, instance_id_); | 771 InPort::EnumerateActivePorts(this, instance_id_); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 723 }) == known_ports->end()) { | 809 }) == known_ports->end()) { |
| 724 size_t index = known_ports->size(); | 810 size_t index = known_ports->size(); |
| 725 port->set_index(index); | 811 port->set_index(index); |
| 726 known_ports->push_back(std::move(port)); | 812 known_ports->push_back(std::move(port)); |
| 727 (*known_ports)[index]->Connect(); | 813 (*known_ports)[index]->Connect(); |
| 728 (*known_ports)[index]->NotifyPortAdded(this); | 814 (*known_ports)[index]->NotifyPortAdded(this); |
| 729 } | 815 } |
| 730 } | 816 } |
| 731 } | 817 } |
| 732 | 818 |
| 819 void DynamicallyInitializedMidiManagerWin::SendOnTaskRunner( | |
| 820 MidiManagerClient* client, | |
| 821 uint32_t port_index, | |
| 822 const std::vector<uint8_t>& data) { | |
| 823 CHECK_GT(port_manager_->outputs()->size(), port_index); | |
| 824 (*port_manager_->outputs())[port_index]->Send(data); | |
| 825 // |client| will be checked inside MidiManager::AccumulateMidiBytesSent. | |
| 826 PostReplyTask( | |
| 827 base::Bind(&DynamicallyInitializedMidiManagerWin::AccumulateMidiBytesSent, | |
| 828 base::Unretained(this), client, data.size())); | |
| 829 } | |
| 830 | |
| 733 } // namespace midi | 831 } // namespace midi |
| OLD | NEW |