| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/audio/win/audio_low_latency_input_win.h" | 5 #include "media/audio/win/audio_low_latency_input_win.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 opened_(false), | 28 opened_(false), |
| 29 started_(false), | 29 started_(false), |
| 30 frame_size_(0), | 30 frame_size_(0), |
| 31 packet_size_frames_(0), | 31 packet_size_frames_(0), |
| 32 packet_size_bytes_(0), | 32 packet_size_bytes_(0), |
| 33 endpoint_buffer_size_frames_(0), | 33 endpoint_buffer_size_frames_(0), |
| 34 device_id_(device_id), | 34 device_id_(device_id), |
| 35 perf_count_to_100ns_units_(0.0), | 35 perf_count_to_100ns_units_(0.0), |
| 36 ms_to_frame_count_(0.0), | 36 ms_to_frame_count_(0.0), |
| 37 sink_(NULL), | 37 sink_(NULL), |
| 38 audio_bus_(media::AudioBus::Create(params)) { | 38 audio_bus_(media::AudioBus::Create(params)), |
| 39 mute_done_(false) { |
| 39 DCHECK(manager_); | 40 DCHECK(manager_); |
| 40 | 41 |
| 41 // Load the Avrt DLL if not already loaded. Required to support MMCSS. | 42 // Load the Avrt DLL if not already loaded. Required to support MMCSS. |
| 42 bool avrt_init = avrt::Initialize(); | 43 bool avrt_init = avrt::Initialize(); |
| 43 DCHECK(avrt_init) << "Failed to load the Avrt.dll"; | 44 DCHECK(avrt_init) << "Failed to load the Avrt.dll"; |
| 44 | 45 |
| 45 // Set up the desired capture format specified by the client. | 46 // Set up the desired capture format specified by the client. |
| 46 format_.nSamplesPerSec = params.sample_rate(); | 47 format_.nSamplesPerSec = params.sample_rate(); |
| 47 format_.wFormatTag = WAVE_FORMAT_PCM; | 48 format_.wFormatTag = WAVE_FORMAT_PCM; |
| 48 format_.wBitsPerSample = params.bits_per_sample(); | 49 format_.wBitsPerSample = params.bits_per_sample(); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 void WASAPIAudioInputStream::Start(AudioInputCallback* callback) { | 129 void WASAPIAudioInputStream::Start(AudioInputCallback* callback) { |
| 129 DCHECK(CalledOnValidThread()); | 130 DCHECK(CalledOnValidThread()); |
| 130 DCHECK(callback); | 131 DCHECK(callback); |
| 131 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; | 132 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; |
| 132 if (!opened_) | 133 if (!opened_) |
| 133 return; | 134 return; |
| 134 | 135 |
| 135 if (started_) | 136 if (started_) |
| 136 return; | 137 return; |
| 137 | 138 |
| 139 if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId && |
| 140 system_audio_volume_) { |
| 141 BOOL muted = false; |
| 142 system_audio_volume_->GetMute(&muted); |
| 143 |
| 144 // If the system audio is muted at the time of capturing, then no need to |
| 145 // mute it again, and later we do not unmute system audio when stopping |
| 146 // capturing. |
| 147 if (!muted) { |
| 148 system_audio_volume_->SetMute(true, NULL); |
| 149 mute_done_ = true; |
| 150 } |
| 151 } |
| 152 |
| 138 DCHECK(!sink_); | 153 DCHECK(!sink_); |
| 139 sink_ = callback; | 154 sink_ = callback; |
| 140 | 155 |
| 141 // Starts periodic AGC microphone measurements if the AGC has been enabled | 156 // Starts periodic AGC microphone measurements if the AGC has been enabled |
| 142 // using SetAutomaticGainControl(). | 157 // using SetAutomaticGainControl(). |
| 143 StartAgc(); | 158 StartAgc(); |
| 144 | 159 |
| 145 // Create and start the thread that will drive the capturing by waiting for | 160 // Create and start the thread that will drive the capturing by waiting for |
| 146 // capture events. | 161 // capture events. |
| 147 capture_thread_ = new base::DelegateSimpleThread( | 162 capture_thread_ = new base::DelegateSimpleThread( |
| (...skipping 10 matching lines...) Expand all Loading... |
| 158 | 173 |
| 159 started_ = SUCCEEDED(hr); | 174 started_ = SUCCEEDED(hr); |
| 160 } | 175 } |
| 161 | 176 |
| 162 void WASAPIAudioInputStream::Stop() { | 177 void WASAPIAudioInputStream::Stop() { |
| 163 DCHECK(CalledOnValidThread()); | 178 DCHECK(CalledOnValidThread()); |
| 164 DVLOG(1) << "WASAPIAudioInputStream::Stop()"; | 179 DVLOG(1) << "WASAPIAudioInputStream::Stop()"; |
| 165 if (!started_) | 180 if (!started_) |
| 166 return; | 181 return; |
| 167 | 182 |
| 183 // We have muted system audio for capturing, so we need to unmute it when |
| 184 // capturing stops. |
| 185 if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId && |
| 186 mute_done_) { |
| 187 DCHECK(system_audio_volume_); |
| 188 if (system_audio_volume_) { |
| 189 system_audio_volume_->SetMute(false, NULL); |
| 190 mute_done_ = false; |
| 191 } |
| 192 } |
| 193 |
| 168 // Stops periodic AGC microphone measurements. | 194 // Stops periodic AGC microphone measurements. |
| 169 StopAgc(); | 195 StopAgc(); |
| 170 | 196 |
| 171 // Shut down the capture thread. | 197 // Shut down the capture thread. |
| 172 if (stop_capture_event_.IsValid()) { | 198 if (stop_capture_event_.IsValid()) { |
| 173 SetEvent(stop_capture_event_.Get()); | 199 SetEvent(stop_capture_event_.Get()); |
| 174 } | 200 } |
| 175 | 201 |
| 176 // Stop the input audio streaming. | 202 // Stop the input audio streaming. |
| 177 HRESULT hr = audio_client_->Stop(); | 203 HRESULT hr = audio_client_->Stop(); |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 | 490 |
| 465 if (device_id_ == AudioDeviceDescription::kDefaultDeviceId) { | 491 if (device_id_ == AudioDeviceDescription::kDefaultDeviceId) { |
| 466 // Retrieve the default capture audio endpoint for the specified role. | 492 // Retrieve the default capture audio endpoint for the specified role. |
| 467 // Note that, in Windows Vista, the MMDevice API supports device roles | 493 // Note that, in Windows Vista, the MMDevice API supports device roles |
| 468 // but the system-supplied user interface programs do not. | 494 // but the system-supplied user interface programs do not. |
| 469 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole, | 495 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole, |
| 470 endpoint_device_.Receive()); | 496 endpoint_device_.Receive()); |
| 471 } else if (device_id_ == AudioDeviceDescription::kCommunicationsDeviceId) { | 497 } else if (device_id_ == AudioDeviceDescription::kCommunicationsDeviceId) { |
| 472 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eCommunications, | 498 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eCommunications, |
| 473 endpoint_device_.Receive()); | 499 endpoint_device_.Receive()); |
| 500 } else if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId) { |
| 501 // Capture the default playback stream. |
| 502 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, |
| 503 endpoint_device_.Receive()); |
| 504 |
| 505 endpoint_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, |
| 506 system_audio_volume_.ReceiveVoid()); |
| 474 } else if (device_id_ == AudioDeviceDescription::kLoopbackInputDeviceId) { | 507 } else if (device_id_ == AudioDeviceDescription::kLoopbackInputDeviceId) { |
| 475 // Capture the default playback stream. | 508 // Capture the default playback stream. |
| 476 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, | 509 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, |
| 477 endpoint_device_.Receive()); | 510 endpoint_device_.Receive()); |
| 478 } else { | 511 } else { |
| 479 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id_).c_str(), | 512 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id_).c_str(), |
| 480 endpoint_device_.Receive()); | 513 endpoint_device_.Receive()); |
| 481 } | 514 } |
| 482 | 515 |
| 483 if (FAILED(hr)) | 516 if (FAILED(hr)) |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported " | 598 DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported " |
| 566 << "but a closest match exists."; | 599 << "but a closest match exists."; |
| 567 return (hr == S_OK); | 600 return (hr == S_OK); |
| 568 } | 601 } |
| 569 | 602 |
| 570 HRESULT WASAPIAudioInputStream::InitializeAudioEngine() { | 603 HRESULT WASAPIAudioInputStream::InitializeAudioEngine() { |
| 571 DWORD flags; | 604 DWORD flags; |
| 572 // Use event-driven mode only fo regular input devices. For loopback the | 605 // Use event-driven mode only fo regular input devices. For loopback the |
| 573 // EVENTCALLBACK flag is specified when intializing | 606 // EVENTCALLBACK flag is specified when intializing |
| 574 // |audio_render_client_for_loopback_|. | 607 // |audio_render_client_for_loopback_|. |
| 575 if (device_id_ == AudioDeviceDescription::kLoopbackInputDeviceId) { | 608 if (device_id_ == AudioDeviceDescription::kLoopbackInputDeviceId || |
| 609 device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId) { |
| 576 flags = AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_NOPERSIST; | 610 flags = AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_NOPERSIST; |
| 577 } else { | 611 } else { |
| 578 flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST; | 612 flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST; |
| 579 } | 613 } |
| 580 | 614 |
| 581 // Initialize the audio stream between the client and the device. | 615 // Initialize the audio stream between the client and the device. |
| 582 // We connect indirectly through the audio engine by using shared mode. | 616 // We connect indirectly through the audio engine by using shared mode. |
| 583 // Note that, |hnsBufferDuration| is set of 0, which ensures that the | 617 // Note that, |hnsBufferDuration| is set of 0, which ensures that the |
| 584 // buffer is never smaller than the minimum buffer size needed to ensure | 618 // buffer is never smaller than the minimum buffer size needed to ensure |
| 585 // that glitches do not occur between the periodic processing passes. | 619 // that glitches do not occur between the periodic processing passes. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 // to MSDN: | 673 // to MSDN: |
| 640 // | 674 // |
| 641 // A pull-mode capture client does not receive any events when a stream is | 675 // A pull-mode capture client does not receive any events when a stream is |
| 642 // initialized with event-driven buffering and is loopback-enabled. To | 676 // initialized with event-driven buffering and is loopback-enabled. To |
| 643 // work around this, initialize a render stream in event-driven mode. Each | 677 // work around this, initialize a render stream in event-driven mode. Each |
| 644 // time the client receives an event for the render stream, it must signal | 678 // time the client receives an event for the render stream, it must signal |
| 645 // the capture client to run the capture thread that reads the next set of | 679 // the capture client to run the capture thread that reads the next set of |
| 646 // samples from the capture endpoint buffer. | 680 // samples from the capture endpoint buffer. |
| 647 // | 681 // |
| 648 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd316551(v=vs.85).a
spx | 682 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd316551(v=vs.85).a
spx |
| 649 if (device_id_ == AudioDeviceDescription::kLoopbackInputDeviceId) { | 683 if (device_id_ == AudioDeviceDescription::kLoopbackInputDeviceId || |
| 684 device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId) { |
| 650 hr = endpoint_device_->Activate( | 685 hr = endpoint_device_->Activate( |
| 651 __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, | 686 __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, |
| 652 audio_render_client_for_loopback_.ReceiveVoid()); | 687 audio_render_client_for_loopback_.ReceiveVoid()); |
| 653 if (FAILED(hr)) | 688 if (FAILED(hr)) |
| 654 return hr; | 689 return hr; |
| 655 | 690 |
| 656 hr = audio_render_client_for_loopback_->Initialize( | 691 hr = audio_render_client_for_loopback_->Initialize( |
| 657 AUDCLNT_SHAREMODE_SHARED, | 692 AUDCLNT_SHAREMODE_SHARED, |
| 658 AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, | 693 AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, |
| 659 0, 0, &format_, NULL); | 694 0, 0, &format_, NULL); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 677 return hr; | 712 return hr; |
| 678 | 713 |
| 679 // Obtain a reference to the ISimpleAudioVolume interface which enables | 714 // Obtain a reference to the ISimpleAudioVolume interface which enables |
| 680 // us to control the master volume level of an audio session. | 715 // us to control the master volume level of an audio session. |
| 681 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), | 716 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), |
| 682 simple_audio_volume_.ReceiveVoid()); | 717 simple_audio_volume_.ReceiveVoid()); |
| 683 return hr; | 718 return hr; |
| 684 } | 719 } |
| 685 | 720 |
| 686 } // namespace media | 721 } // namespace media |
| OLD | NEW |