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