OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/midi/midi_manager_win.h" | 5 #include "media/midi/midi_manager_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 | 8 |
9 // Prevent unnecessary functions from being included from <mmsystem.h> | 9 // Prevent unnecessary functions from being included from <mmsystem.h> |
10 #define MMNODRV | 10 #define MMNODRV |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 typedef scoped_ptr<MIDIHDR, MIDIHDRDeleter> ScopedMIDIHDR; | 69 typedef scoped_ptr<MIDIHDR, MIDIHDRDeleter> ScopedMIDIHDR; |
70 | 70 |
71 ScopedMIDIHDR CreateMIDIHDR(size_t size) { | 71 ScopedMIDIHDR CreateMIDIHDR(size_t size) { |
72 ScopedMIDIHDR header(new MIDIHDR); | 72 ScopedMIDIHDR header(new MIDIHDR); |
73 ZeroMemory(header.get(), sizeof(*header)); | 73 ZeroMemory(header.get(), sizeof(*header)); |
74 header->lpData = new char[size]; | 74 header->lpData = new char[size]; |
75 header->dwBufferLength = size; | 75 header->dwBufferLength = size; |
76 return header.Pass(); | 76 return header.Pass(); |
77 } | 77 } |
78 | 78 |
79 void SendShortMIDIMessageInternal(HMIDIOUT midi_out_handle, | 79 void SendShortMidiMessageInternal(HMIDIOUT midi_out_handle, |
80 const std::vector<uint8>& message) { | 80 const std::vector<uint8>& message) { |
81 if (message.size() >= 4) | 81 if (message.size() >= 4) |
82 return; | 82 return; |
83 | 83 |
84 DWORD packed_message = 0; | 84 DWORD packed_message = 0; |
85 for (size_t i = 0; i < message.size(); ++i) | 85 for (size_t i = 0; i < message.size(); ++i) |
86 packed_message |= (static_cast<uint32>(message[i]) << (i * 8)); | 86 packed_message |= (static_cast<uint32>(message[i]) << (i * 8)); |
87 MMRESULT result = midiOutShortMsg(midi_out_handle, packed_message); | 87 MMRESULT result = midiOutShortMsg(midi_out_handle, packed_message); |
88 DLOG_IF(ERROR, result != MMSYSERR_NOERROR) | 88 DLOG_IF(ERROR, result != MMSYSERR_NOERROR) |
89 << "Failed to output short message: " << GetOutErrorMessage(result); | 89 << "Failed to output short message: " << GetOutErrorMessage(result); |
90 } | 90 } |
91 | 91 |
92 void SendLongMIDIMessageInternal(HMIDIOUT midi_out_handle, | 92 void SendLongMidiMessageInternal(HMIDIOUT midi_out_handle, |
93 const std::vector<uint8>& message) { | 93 const std::vector<uint8>& message) { |
94 // Implementation note: | 94 // Implementation note: |
95 // Sending long MIDI message can be performed synchronously or asynchronously | 95 // Sending long MIDI message can be performed synchronously or asynchronously |
96 // depending on the driver. There are 2 options to support both cases: | 96 // depending on the driver. There are 2 options to support both cases: |
97 // 1) Call midiOutLongMsg() API and wait for its completion within this | 97 // 1) Call midiOutLongMsg() API and wait for its completion within this |
98 // function. In this approach, we can avoid memory copy by directly pointing | 98 // function. In this approach, we can avoid memory copy by directly pointing |
99 // |message| as the data buffer to be sent. | 99 // |message| as the data buffer to be sent. |
100 // 2) Allocate a buffer and copy |message| to it, then call midiOutLongMsg() | 100 // 2) Allocate a buffer and copy |message| to it, then call midiOutLongMsg() |
101 // API. The buffer will be freed in the MOM_DONE event hander, which tells | 101 // API. The buffer will be freed in the MOM_DONE event hander, which tells |
102 // us that the task of midiOutLongMsg() API is completed. | 102 // us that the task of midiOutLongMsg() API is completed. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 << GetOutErrorMessage(result); | 140 << GetOutErrorMessage(result); |
141 return; | 141 return; |
142 } | 142 } |
143 | 143 |
144 // The ownership of |midi_header| is moved to MOM_DONE event handler. | 144 // The ownership of |midi_header| is moved to MOM_DONE event handler. |
145 midi_header.release(); | 145 midi_header.release(); |
146 } | 146 } |
147 | 147 |
148 } // namespace | 148 } // namespace |
149 | 149 |
150 class MIDIManagerWin::InDeviceInfo { | 150 class MidiManagerWin::InDeviceInfo { |
151 public: | 151 public: |
152 ~InDeviceInfo() { | 152 ~InDeviceInfo() { |
153 Uninitialize(); | 153 Uninitialize(); |
154 } | 154 } |
155 void set_port_index(int index) { | 155 void set_port_index(int index) { |
156 port_index_ = index; | 156 port_index_ = index; |
157 } | 157 } |
158 int port_index() const { | 158 int port_index() const { |
159 return port_index_; | 159 return port_index_; |
160 } | 160 } |
161 bool device_to_be_closed() const { | 161 bool device_to_be_closed() const { |
162 return device_to_be_closed_; | 162 return device_to_be_closed_; |
163 } | 163 } |
164 HMIDIIN midi_handle() const { | 164 HMIDIIN midi_handle() const { |
165 return midi_handle_; | 165 return midi_handle_; |
166 } | 166 } |
167 | 167 |
168 static scoped_ptr<InDeviceInfo> Create(MIDIManagerWin* manager, | 168 static scoped_ptr<InDeviceInfo> Create(MidiManagerWin* manager, |
169 UINT device_id) { | 169 UINT device_id) { |
170 scoped_ptr<InDeviceInfo> obj(new InDeviceInfo(manager)); | 170 scoped_ptr<InDeviceInfo> obj(new InDeviceInfo(manager)); |
171 if (!obj->Initialize(device_id)) | 171 if (!obj->Initialize(device_id)) |
172 obj.reset(); | 172 obj.reset(); |
173 return obj.Pass(); | 173 return obj.Pass(); |
174 } | 174 } |
175 | 175 |
176 private: | 176 private: |
177 static const int kInvalidPortIndex = -1; | 177 static const int kInvalidPortIndex = -1; |
178 static const size_t kBufferLength = 32 * 1024; | 178 static const size_t kBufferLength = 32 * 1024; |
179 | 179 |
180 explicit InDeviceInfo(MIDIManagerWin* manager) | 180 explicit InDeviceInfo(MidiManagerWin* manager) |
181 : manager_(manager), | 181 : manager_(manager), |
182 port_index_(kInvalidPortIndex), | 182 port_index_(kInvalidPortIndex), |
183 midi_handle_(NULL), | 183 midi_handle_(NULL), |
184 started_(false), | 184 started_(false), |
185 device_to_be_closed_(false) { | 185 device_to_be_closed_(false) { |
186 } | 186 } |
187 | 187 |
188 bool Initialize(DWORD device_id) { | 188 bool Initialize(DWORD device_id) { |
189 Uninitialize(); | 189 Uninitialize(); |
190 midi_header_ = CreateMIDIHDR(kBufferLength); | 190 midi_header_ = CreateMIDIHDR(kBufferLength); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 return; | 290 return; |
291 } | 291 } |
292 } | 292 } |
293 | 293 |
294 void OnShortMessageReceived(uint8 status_byte, | 294 void OnShortMessageReceived(uint8 status_byte, |
295 uint8 first_data_byte, | 295 uint8 first_data_byte, |
296 uint8 second_data_byte, | 296 uint8 second_data_byte, |
297 DWORD elapsed_ms) { | 297 DWORD elapsed_ms) { |
298 if (device_to_be_closed()) | 298 if (device_to_be_closed()) |
299 return; | 299 return; |
300 const size_t len = GetMIDIMessageLength(status_byte); | 300 const size_t len = GetMidiMessageLength(status_byte); |
301 if (len == 0 || port_index() == kInvalidPortIndex) | 301 if (len == 0 || port_index() == kInvalidPortIndex) |
302 return; | 302 return; |
303 const uint8 kData[] = { status_byte, first_data_byte, second_data_byte }; | 303 const uint8 kData[] = { status_byte, first_data_byte, second_data_byte }; |
304 DCHECK_LE(len, arraysize(kData)); | 304 DCHECK_LE(len, arraysize(kData)); |
305 OnMessageReceived(kData, len, elapsed_ms); | 305 OnMessageReceived(kData, len, elapsed_ms); |
306 } | 306 } |
307 | 307 |
308 void OnLongMessageReceived(MIDIHDR* header, DWORD elapsed_ms) { | 308 void OnLongMessageReceived(MIDIHDR* header, DWORD elapsed_ms) { |
309 if (header != midi_header_.get()) | 309 if (header != midi_header_.get()) |
310 return; | 310 return; |
(...skipping 19 matching lines...) Expand all Loading... |
330 << "Failed to attach input port: " << GetInErrorMessage(result); | 330 << "Failed to attach input port: " << GetInErrorMessage(result); |
331 } | 331 } |
332 | 332 |
333 void OnMessageReceived(const uint8* data, size_t length, DWORD elapsed_ms) { | 333 void OnMessageReceived(const uint8* data, size_t length, DWORD elapsed_ms) { |
334 // MIM_DATA/MIM_LONGDATA message treats the time when midiInStart() is | 334 // MIM_DATA/MIM_LONGDATA message treats the time when midiInStart() is |
335 // called as the origin of |elapsed_ms|. | 335 // called as the origin of |elapsed_ms|. |
336 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd757284.aspx | 336 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd757284.aspx |
337 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd757286.aspx | 337 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd757286.aspx |
338 const base::TimeTicks event_time = | 338 const base::TimeTicks event_time = |
339 start_time_ + base::TimeDelta::FromMilliseconds(elapsed_ms); | 339 start_time_ + base::TimeDelta::FromMilliseconds(elapsed_ms); |
340 // MIDIManager::ReceiveMIDIData() expects |timestamp| as the elapsed seconds | 340 // MidiManager::ReceiveMidiData() expects |timestamp| as the elapsed seconds |
341 // from base::TimeTicks::Now(). | 341 // from base::TimeTicks::Now(). |
342 // TODO(yukawa): Update MIDIManager::ReceiveMIDIData() so that it can | 342 // TODO(yukawa): Update MidiManager::ReceiveMidiData() so that it can |
343 // receive |event_time| directly if the precision of base::TimeTicks is | 343 // receive |event_time| directly if the precision of base::TimeTicks is |
344 // sufficient. | 344 // sufficient. |
345 const double timestamp = (event_time - base::TimeTicks()).InSecondsF(); | 345 const double timestamp = (event_time - base::TimeTicks()).InSecondsF(); |
346 manager_->ReceiveMIDIData(port_index_, data, length, timestamp); | 346 manager_->ReceiveMidiData(port_index_, data, length, timestamp); |
347 } | 347 } |
348 | 348 |
349 MIDIManagerWin* manager_; | 349 MidiManagerWin* manager_; |
350 int port_index_; | 350 int port_index_; |
351 HMIDIIN midi_handle_; | 351 HMIDIIN midi_handle_; |
352 ScopedMIDIHDR midi_header_; | 352 ScopedMIDIHDR midi_header_; |
353 base::TimeTicks start_time_; | 353 base::TimeTicks start_time_; |
354 bool started_; | 354 bool started_; |
355 bool device_to_be_closed_; | 355 bool device_to_be_closed_; |
356 DISALLOW_COPY_AND_ASSIGN(MIDIManagerWin::InDeviceInfo); | 356 DISALLOW_COPY_AND_ASSIGN(MidiManagerWin::InDeviceInfo); |
357 }; | 357 }; |
358 | 358 |
359 class MIDIManagerWin::OutDeviceInfo { | 359 class MidiManagerWin::OutDeviceInfo { |
360 public: | 360 public: |
361 ~OutDeviceInfo() { | 361 ~OutDeviceInfo() { |
362 Uninitialize(); | 362 Uninitialize(); |
363 } | 363 } |
364 | 364 |
365 static scoped_ptr<OutDeviceInfo> Create(UINT device_id) { | 365 static scoped_ptr<OutDeviceInfo> Create(UINT device_id) { |
366 scoped_ptr<OutDeviceInfo> obj(new OutDeviceInfo); | 366 scoped_ptr<OutDeviceInfo> obj(new OutDeviceInfo); |
367 if (!obj->Initialize(device_id)) | 367 if (!obj->Initialize(device_id)) |
368 obj.reset(); | 368 obj.reset(); |
369 return obj.Pass(); | 369 return obj.Pass(); |
(...skipping 12 matching lines...) Expand all Loading... |
382 if (!midi_handle_) | 382 if (!midi_handle_) |
383 return; | 383 return; |
384 | 384 |
385 // Give up sending MIDI messages here if the device is already closed. | 385 // Give up sending MIDI messages here if the device is already closed. |
386 // Note that this check is optional. Regardless of that we check |closed_| | 386 // Note that this check is optional. Regardless of that we check |closed_| |
387 // or not, nothing harmful happens as long as |midi_handle_| is still valid. | 387 // or not, nothing harmful happens as long as |midi_handle_| is still valid. |
388 if (closed_) | 388 if (closed_) |
389 return; | 389 return; |
390 | 390 |
391 // MIDI Running status must be filtered out. | 391 // MIDI Running status must be filtered out. |
392 MIDIMessageQueue message_queue(false); | 392 MidiMessageQueue message_queue(false); |
393 message_queue.Add(data); | 393 message_queue.Add(data); |
394 std::vector<uint8> message; | 394 std::vector<uint8> message; |
395 while (!quitting_) { | 395 while (!quitting_) { |
396 message_queue.Get(&message); | 396 message_queue.Get(&message); |
397 if (message.empty()) | 397 if (message.empty()) |
398 break; | 398 break; |
399 // SendShortMIDIMessageInternal can send a MIDI message up to 3 bytes. | 399 // SendShortMidiMessageInternal can send a MIDI message up to 3 bytes. |
400 if (message.size() <= 3) | 400 if (message.size() <= 3) |
401 SendShortMIDIMessageInternal(midi_handle_, message); | 401 SendShortMidiMessageInternal(midi_handle_, message); |
402 else | 402 else |
403 SendLongMIDIMessageInternal(midi_handle_, message); | 403 SendLongMidiMessageInternal(midi_handle_, message); |
404 } | 404 } |
405 } | 405 } |
406 | 406 |
407 private: | 407 private: |
408 OutDeviceInfo() | 408 OutDeviceInfo() |
409 : midi_handle_(NULL), | 409 : midi_handle_(NULL), |
410 closed_(false), | 410 closed_(false), |
411 quitting_(false) {} | 411 quitting_(false) {} |
412 | 412 |
413 bool Initialize(DWORD device_id) { | 413 bool Initialize(DWORD device_id) { |
414 Uninitialize(); | 414 Uninitialize(); |
415 // Here we use |CALLBACK_FUNCTION| to subscribe MOM_DONE and MOM_CLOSE | 415 // Here we use |CALLBACK_FUNCTION| to subscribe MOM_DONE and MOM_CLOSE |
416 // events. | 416 // events. |
417 // - MOM_DONE: SendLongMIDIMessageInternal() relies on this event to clean | 417 // - MOM_DONE: SendLongMidiMessageInternal() relies on this event to clean |
418 // up the backing store where a long MIDI message is stored. | 418 // up the backing store where a long MIDI message is stored. |
419 // - MOM_CLOSE: This event is sent when 1) midiOutClose() is called, or 2) | 419 // - MOM_CLOSE: This event is sent when 1) midiOutClose() is called, or 2) |
420 // the MIDI device becomes unavailable for some reasons, e.g., the cable | 420 // the MIDI device becomes unavailable for some reasons, e.g., the cable |
421 // is disconnected. As for the former case, HMIDIOUT will be invalidated | 421 // is disconnected. As for the former case, HMIDIOUT will be invalidated |
422 // soon after the callback is finished. As for the later case, however, | 422 // soon after the callback is finished. As for the later case, however, |
423 // HMIDIOUT continues to be valid until midiOutClose() is called. | 423 // HMIDIOUT continues to be valid until midiOutClose() is called. |
424 MMRESULT result = midiOutOpen(&midi_handle_, | 424 MMRESULT result = midiOutOpen(&midi_handle_, |
425 device_id, | 425 device_id, |
426 reinterpret_cast<DWORD_PTR>(&HandleMessage), | 426 reinterpret_cast<DWORD_PTR>(&HandleMessage), |
427 reinterpret_cast<DWORD_PTR>(this), | 427 reinterpret_cast<DWORD_PTR>(this), |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 // TODO(yukawa): Implement crbug.com/279097. | 483 // TODO(yukawa): Implement crbug.com/279097. |
484 return; | 484 return; |
485 } | 485 } |
486 } | 486 } |
487 | 487 |
488 HMIDIOUT midi_handle_; | 488 HMIDIOUT midi_handle_; |
489 | 489 |
490 // True if the device is already closed. | 490 // True if the device is already closed. |
491 volatile bool closed_; | 491 volatile bool closed_; |
492 | 492 |
493 // True if the MIDIManagerWin is trying to stop the sender thread. | 493 // True if the MidiManagerWin is trying to stop the sender thread. |
494 volatile bool quitting_; | 494 volatile bool quitting_; |
495 | 495 |
496 DISALLOW_COPY_AND_ASSIGN(MIDIManagerWin::OutDeviceInfo); | 496 DISALLOW_COPY_AND_ASSIGN(MidiManagerWin::OutDeviceInfo); |
497 }; | 497 }; |
498 | 498 |
499 MIDIManagerWin::MIDIManagerWin() | 499 MidiManagerWin::MidiManagerWin() |
500 : send_thread_("MIDISendThread") { | 500 : send_thread_("MidiSendThread") { |
501 } | 501 } |
502 | 502 |
503 bool MIDIManagerWin::Initialize() { | 503 bool MidiManagerWin::Initialize() { |
504 const UINT num_in_devices = midiInGetNumDevs(); | 504 const UINT num_in_devices = midiInGetNumDevs(); |
505 in_devices_.reserve(num_in_devices); | 505 in_devices_.reserve(num_in_devices); |
506 for (UINT device_id = 0; device_id < num_in_devices; ++device_id) { | 506 for (UINT device_id = 0; device_id < num_in_devices; ++device_id) { |
507 MIDIINCAPS caps = {}; | 507 MIDIINCAPS caps = {}; |
508 MMRESULT result = midiInGetDevCaps(device_id, &caps, sizeof(caps)); | 508 MMRESULT result = midiInGetDevCaps(device_id, &caps, sizeof(caps)); |
509 if (result != MMSYSERR_NOERROR) { | 509 if (result != MMSYSERR_NOERROR) { |
510 DLOG(ERROR) << "Failed to obtain input device info: " | 510 DLOG(ERROR) << "Failed to obtain input device info: " |
511 << GetInErrorMessage(result); | 511 << GetInErrorMessage(result); |
512 continue; | 512 continue; |
513 } | 513 } |
514 scoped_ptr<InDeviceInfo> in_device(InDeviceInfo::Create(this, device_id)); | 514 scoped_ptr<InDeviceInfo> in_device(InDeviceInfo::Create(this, device_id)); |
515 if (!in_device) | 515 if (!in_device) |
516 continue; | 516 continue; |
517 MIDIPortInfo info( | 517 MidiPortInfo info( |
518 base::IntToString(static_cast<int>(device_id)), | 518 base::IntToString(static_cast<int>(device_id)), |
519 "", | 519 "", |
520 base::WideToUTF8(caps.szPname), | 520 base::WideToUTF8(caps.szPname), |
521 base::IntToString(static_cast<int>(caps.vDriverVersion))); | 521 base::IntToString(static_cast<int>(caps.vDriverVersion))); |
522 AddInputPort(info); | 522 AddInputPort(info); |
523 in_device->set_port_index(input_ports_.size() - 1); | 523 in_device->set_port_index(input_ports_.size() - 1); |
524 in_devices_.push_back(in_device.Pass()); | 524 in_devices_.push_back(in_device.Pass()); |
525 } | 525 } |
526 | 526 |
527 const UINT num_out_devices = midiOutGetNumDevs(); | 527 const UINT num_out_devices = midiOutGetNumDevs(); |
528 out_devices_.reserve(num_out_devices); | 528 out_devices_.reserve(num_out_devices); |
529 for (UINT device_id = 0; device_id < num_out_devices; ++device_id) { | 529 for (UINT device_id = 0; device_id < num_out_devices; ++device_id) { |
530 MIDIOUTCAPS caps = {}; | 530 MIDIOUTCAPS caps = {}; |
531 MMRESULT result = midiOutGetDevCaps(device_id, &caps, sizeof(caps)); | 531 MMRESULT result = midiOutGetDevCaps(device_id, &caps, sizeof(caps)); |
532 if (result != MMSYSERR_NOERROR) { | 532 if (result != MMSYSERR_NOERROR) { |
533 DLOG(ERROR) << "Failed to obtain output device info: " | 533 DLOG(ERROR) << "Failed to obtain output device info: " |
534 << GetOutErrorMessage(result); | 534 << GetOutErrorMessage(result); |
535 continue; | 535 continue; |
536 } | 536 } |
537 scoped_ptr<OutDeviceInfo> out_port(OutDeviceInfo::Create(device_id)); | 537 scoped_ptr<OutDeviceInfo> out_port(OutDeviceInfo::Create(device_id)); |
538 if (!out_port) | 538 if (!out_port) |
539 continue; | 539 continue; |
540 MIDIPortInfo info( | 540 MidiPortInfo info( |
541 base::IntToString(static_cast<int>(device_id)), | 541 base::IntToString(static_cast<int>(device_id)), |
542 "", | 542 "", |
543 base::WideToUTF8(caps.szPname), | 543 base::WideToUTF8(caps.szPname), |
544 base::IntToString(static_cast<int>(caps.vDriverVersion))); | 544 base::IntToString(static_cast<int>(caps.vDriverVersion))); |
545 AddOutputPort(info); | 545 AddOutputPort(info); |
546 out_devices_.push_back(out_port.Pass()); | 546 out_devices_.push_back(out_port.Pass()); |
547 } | 547 } |
548 | 548 |
549 return true; | 549 return true; |
550 } | 550 } |
551 | 551 |
552 MIDIManagerWin::~MIDIManagerWin() { | 552 MidiManagerWin::~MidiManagerWin() { |
553 // Cleanup order is important. |send_thread_| must be stopped before | 553 // Cleanup order is important. |send_thread_| must be stopped before |
554 // |out_devices_| is cleared. | 554 // |out_devices_| is cleared. |
555 for (size_t i = 0; i < output_ports_.size(); ++i) | 555 for (size_t i = 0; i < output_ports_.size(); ++i) |
556 out_devices_[i]->Quit(); | 556 out_devices_[i]->Quit(); |
557 send_thread_.Stop(); | 557 send_thread_.Stop(); |
558 | 558 |
559 out_devices_.clear(); | 559 out_devices_.clear(); |
560 output_ports_.clear(); | 560 output_ports_.clear(); |
561 in_devices_.clear(); | 561 in_devices_.clear(); |
562 input_ports_.clear(); | 562 input_ports_.clear(); |
563 } | 563 } |
564 | 564 |
565 void MIDIManagerWin::DispatchSendMIDIData(MIDIManagerClient* client, | 565 void MidiManagerWin::DispatchSendMidiData(MidiManagerClient* client, |
566 uint32 port_index, | 566 uint32 port_index, |
567 const std::vector<uint8>& data, | 567 const std::vector<uint8>& data, |
568 double timestamp) { | 568 double timestamp) { |
569 if (out_devices_.size() <= port_index) | 569 if (out_devices_.size() <= port_index) |
570 return; | 570 return; |
571 | 571 |
572 base::TimeDelta delay; | 572 base::TimeDelta delay; |
573 if (timestamp != 0.0) { | 573 if (timestamp != 0.0) { |
574 base::TimeTicks time_to_send = | 574 base::TimeTicks time_to_send = |
575 base::TimeTicks() + base::TimeDelta::FromMicroseconds( | 575 base::TimeTicks() + base::TimeDelta::FromMicroseconds( |
576 timestamp * base::Time::kMicrosecondsPerSecond); | 576 timestamp * base::Time::kMicrosecondsPerSecond); |
577 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); | 577 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); |
578 } | 578 } |
579 | 579 |
580 if (!send_thread_.IsRunning()) | 580 if (!send_thread_.IsRunning()) |
581 send_thread_.Start(); | 581 send_thread_.Start(); |
582 | 582 |
583 OutDeviceInfo* out_port = out_devices_[port_index].get(); | 583 OutDeviceInfo* out_port = out_devices_[port_index].get(); |
584 send_thread_.message_loop()->PostDelayedTask( | 584 send_thread_.message_loop()->PostDelayedTask( |
585 FROM_HERE, | 585 FROM_HERE, |
586 base::Bind(&OutDeviceInfo::Send, base::Unretained(out_port), data), | 586 base::Bind(&OutDeviceInfo::Send, base::Unretained(out_port), data), |
587 delay); | 587 delay); |
588 | 588 |
589 // Call back AccumulateMIDIBytesSent() on |send_thread_| to emulate the | 589 // Call back AccumulateMidiBytesSent() on |send_thread_| to emulate the |
590 // behavior of MIDIManagerMac::SendMIDIData. | 590 // behavior of MidiManagerMac::SendMidiData. |
591 // TODO(yukawa): Do this task in a platform-independent way if possible. | 591 // TODO(yukawa): Do this task in a platform-independent way if possible. |
592 // See crbug.com/325810. | 592 // See crbug.com/325810. |
593 send_thread_.message_loop()->PostTask( | 593 send_thread_.message_loop()->PostTask( |
594 FROM_HERE, | 594 FROM_HERE, |
595 base::Bind(&MIDIManagerClient::AccumulateMIDIBytesSent, | 595 base::Bind(&MidiManagerClient::AccumulateMidiBytesSent, |
596 base::Unretained(client), data.size())); | 596 base::Unretained(client), data.size())); |
597 } | 597 } |
598 | 598 |
599 MIDIManager* MIDIManager::Create() { | 599 MidiManager* MidiManager::Create() { |
600 return new MIDIManagerWin(); | 600 return new MidiManagerWin(); |
601 } | 601 } |
602 | 602 |
603 } // namespace media | 603 } // namespace media |
OLD | NEW |