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

Side by Side Diff: media/midi/dynamically_initialized_midi_manager_win.cc

Issue 2698413003: Web MIDI: implement sending for dynamic manager instantiation on Windows (Closed)
Patch Set: review #4 Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/midi/dynamically_initialized_midi_manager_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/midi/dynamically_initialized_midi_manager_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698