| 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 |