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 |