blob: 0d901947c2d3d09c37428d49a451e245e963fbcd [file] [log] [blame]
[email protected]c9bdcbd2012-07-19 23:35:541// 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
3// found in the LICENSE file.
4
[email protected]91d3a7d2012-08-22 00:56:555#include "remoting/host/audio_capturer_win.h"
6
[email protected]c9bdcbd2012-07-19 23:35:547#include <avrt.h>
[email protected]c9bdcbd2012-07-19 23:35:548#include <mmreg.h>
9#include <mmsystem.h>
robliao6fc41c62017-04-28 22:41:1710#include <objbase.h>
avic5960f32015-12-22 22:49:4811#include <stdint.h>
[email protected]07cb35f2012-07-31 23:10:1012#include <stdlib.h>
sergeyu1417e0132015-12-23 19:01:2213#include <windows.h>
14
avic5960f32015-12-22 22:49:4815#include <algorithm>
sergeyu1417e0132015-12-23 19:01:2216#include <utility>
[email protected]07cb35f2012-07-31 23:10:1017
[email protected]c9bdcbd2012-07-19 23:35:5418#include "base/logging.h"
dcheng0765c492016-04-06 22:41:5319#include "base/memory/ptr_util.h"
zijieheb40182a2016-07-24 19:28:1520#include "base/synchronization/lock.h"
zijiehe00c53fe2017-04-24 23:33:0521#include "remoting/host/win/default_audio_device_change_detector.h"
[email protected]c9bdcbd2012-07-19 23:35:5422
23namespace {
[email protected]881de5e2013-01-02 23:11:1424const int kBytesPerSample = 2;
25const int kBitsPerSample = kBytesPerSample * 8;
[email protected]c9bdcbd2012-07-19 23:35:5426// Conversion factor from 100ns to 1ms.
[email protected]37a770b02012-08-17 00:13:1727const int k100nsPerMillisecond = 10000;
[email protected]07cb35f2012-07-31 23:10:1028
29// Tolerance for catching packets of silence. If all samples have absolute
30// value less than this threshold, the packet will be counted as a packet of
31// silence. A value of 2 was chosen, because Windows can give samples of 1 and
32// -1, even when no audio is playing.
33const int kSilenceThreshold = 2;
[email protected]37a770b02012-08-17 00:13:1734
35// Lower bound for timer intervals, in milliseconds.
36const int kMinTimerInterval = 30;
37
38// Upper bound for the timer precision error, in milliseconds.
39// Timers are supposed to be accurate to 20ms, so we use 30ms to be safe.
40const int kMaxExpectedTimerLag = 30;
zijiehec3315982017-06-10 01:22:0941
[email protected]c9bdcbd2012-07-19 23:35:5442} // namespace
43
44namespace remoting {
45
[email protected]ca1488912012-07-27 17:19:0446AudioCapturerWin::AudioCapturerWin()
[email protected]881de5e2013-01-02 23:11:1447 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
zijiehe26fe0da2017-05-23 04:34:1148 volume_filter_(kSilenceThreshold),
[email protected]a21883d2013-03-16 09:14:5149 last_capture_error_(S_OK) {
zijieheb40182a2016-07-24 19:28:1550 thread_checker_.DetachFromThread();
[email protected]c9bdcbd2012-07-19 23:35:5451}
52
53AudioCapturerWin::~AudioCapturerWin() {
sergeyu7bc87602015-02-13 20:33:2854 DCHECK(thread_checker_.CalledOnValidThread());
zijiehe00c53fe2017-04-24 23:33:0555 Deinitialize();
[email protected]c9bdcbd2012-07-19 23:35:5456}
57
[email protected]339abeca2012-07-20 18:28:2458bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
zijieheb40182a2016-07-24 19:28:1559 callback_ = callback;
60
61 if (!Initialize()) {
62 return false;
63 }
64
65 // Initialize the capture timer and start capturing. Note, this timer won't
66 // be reset or restarted in ResetAndInitialize() function. Which means we
67 // expect the audio_device_period_ is a system wide configuration, it would
68 // not be changed with the default audio device.
69 capture_timer_.reset(new base::RepeatingTimer());
70 capture_timer_->Start(FROM_HERE, audio_device_period_, this,
71 &AudioCapturerWin::DoCapture);
72 return true;
73}
74
75bool AudioCapturerWin::ResetAndInitialize() {
76 Deinitialize();
77 if (!Initialize()) {
78 Deinitialize();
79 return false;
80 }
81 return true;
82}
83
84void AudioCapturerWin::Deinitialize() {
85 DCHECK(thread_checker_.CalledOnValidThread());
86 wave_format_ex_.Reset(nullptr);
zijiehe00c53fe2017-04-24 23:33:0587 default_device_detector_.reset();
robliao9212cb42017-04-06 17:43:3988 audio_capture_client_.Reset();
zijiehe00c53fe2017-04-24 23:33:0589 if (audio_client_) {
90 audio_client_->Stop();
91 }
robliao9212cb42017-04-06 17:43:3992 audio_client_.Reset();
93 mm_device_.Reset();
zijieheb40182a2016-07-24 19:28:1594}
95
96bool AudioCapturerWin::Initialize() {
robliaob44b9072017-04-19 00:28:0997 DCHECK(!audio_capture_client_.Get());
98 DCHECK(!audio_client_.Get());
99 DCHECK(!mm_device_.Get());
sergeyuc5f104b2015-01-09 19:33:24100 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr);
[email protected]c9bdcbd2012-07-19 23:35:54101 DCHECK(thread_checker_.CalledOnValidThread());
102
[email protected]c9bdcbd2012-07-19 23:35:54103 HRESULT hr = S_OK;
Robert Liao1a378352017-10-18 01:31:17104 Microsoft::WRL::ComPtr<IMMDeviceEnumerator> mm_device_enumerator;
robliaoeb9bfd642017-05-18 17:35:16105 hr = ::CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
106 IID_PPV_ARGS(&mm_device_enumerator));
[email protected]c9bdcbd2012-07-19 23:35:54107 if (FAILED(hr)) {
108 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24109 return false;
[email protected]c9bdcbd2012-07-19 23:35:54110 }
111
zijiehe00c53fe2017-04-24 23:33:05112 default_device_detector_.reset(
113 new DefaultAudioDeviceChangeDetector(mm_device_enumerator));
zijieheb40182a2016-07-24 19:28:15114
[email protected]c9bdcbd2012-07-19 23:35:54115 // Get the audio endpoint.
zijiehe00c53fe2017-04-24 23:33:05116 hr = mm_device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
robliao310fa98b2017-05-11 17:14:00117 mm_device_.GetAddressOf());
[email protected]c9bdcbd2012-07-19 23:35:54118 if (FAILED(hr)) {
119 LOG(ERROR) << "Failed to get IMMDevice. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24120 return false;
[email protected]c9bdcbd2012-07-19 23:35:54121 }
122
123 // Get an audio client.
124 hr = mm_device_->Activate(__uuidof(IAudioClient),
125 CLSCTX_ALL,
sergeyuc5f104b2015-01-09 19:33:24126 nullptr,
robliao6fc41c62017-04-28 22:41:17127 &audio_client_);
[email protected]c9bdcbd2012-07-19 23:35:54128 if (FAILED(hr)) {
129 LOG(ERROR) << "Failed to get an IAudioClient. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24130 return false;
[email protected]c9bdcbd2012-07-19 23:35:54131 }
132
133 REFERENCE_TIME device_period;
sergeyuc5f104b2015-01-09 19:33:24134 hr = audio_client_->GetDevicePeriod(&device_period, nullptr);
[email protected]c9bdcbd2012-07-19 23:35:54135 if (FAILED(hr)) {
136 LOG(ERROR) << "IAudioClient::GetDevicePeriod failed. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24137 return false;
[email protected]c9bdcbd2012-07-19 23:35:54138 }
[email protected]37a770b02012-08-17 00:13:17139 // We round up, if |device_period| / |k100nsPerMillisecond|
140 // is not a whole number.
141 int device_period_in_milliseconds =
142 1 + ((device_period - 1) / k100nsPerMillisecond);
[email protected]c9bdcbd2012-07-19 23:35:54143 audio_device_period_ = base::TimeDelta::FromMilliseconds(
[email protected]37a770b02012-08-17 00:13:17144 std::max(device_period_in_milliseconds, kMinTimerInterval));
[email protected]c9bdcbd2012-07-19 23:35:54145
146 // Get the wave format.
147 hr = audio_client_->GetMixFormat(&wave_format_ex_);
148 if (FAILED(hr)) {
149 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24150 return false;
[email protected]c9bdcbd2012-07-19 23:35:54151 }
152
zijiehec3315982017-06-10 01:22:09153 if (wave_format_ex_->wFormatTag != WAVE_FORMAT_IEEE_FLOAT &&
154 wave_format_ex_->wFormatTag != WAVE_FORMAT_PCM &&
155 wave_format_ex_->wFormatTag != WAVE_FORMAT_EXTENSIBLE) {
156 LOG(ERROR) << "Failed to force 16-bit PCM";
157 return false;
158 }
[email protected]ca1488912012-07-27 17:19:04159
zijiehec3315982017-06-10 01:22:09160 if (!AudioCapturer::IsValidSampleRate(wave_format_ex_->nSamplesPerSec)) {
161 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz. "
162 << wave_format_ex_->nSamplesPerSec;
163 return false;
164 }
[email protected]ca1488912012-07-27 17:19:04165
zijiehec3315982017-06-10 01:22:09166 // We support from mono to 7.1. This check should be consistent with
167 // AudioPacket::Channels.
168 if (wave_format_ex_->nChannels > 8 || wave_format_ex_->nChannels <= 0) {
169 LOG(ERROR) << "Unsupported channels " << wave_format_ex_->nChannels;
170 return false;
171 }
[email protected]c9bdcbd2012-07-19 23:35:54172
zijiehec3315982017-06-10 01:22:09173 sampling_rate_ = static_cast<AudioPacket::SamplingRate>(
174 wave_format_ex_->nSamplesPerSec);
175
176 wave_format_ex_->wBitsPerSample = kBitsPerSample;
177 wave_format_ex_->nBlockAlign = wave_format_ex_->nChannels * kBytesPerSample;
178 wave_format_ex_->nAvgBytesPerSec =
179 sampling_rate_ * wave_format_ex_->nBlockAlign;
180
181 if (wave_format_ex_->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
182 PWAVEFORMATEXTENSIBLE wave_format_extensible =
183 reinterpret_cast<WAVEFORMATEXTENSIBLE*>(
184 static_cast<WAVEFORMATEX*>(wave_format_ex_));
185 if (!IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
186 wave_format_extensible->SubFormat) &&
187 !IsEqualGUID(KSDATAFORMAT_SUBTYPE_PCM,
188 wave_format_extensible->SubFormat)) {
189 LOG(ERROR) << "Failed to force 16-bit samples";
[email protected]339abeca2012-07-20 18:28:24190 return false;
zijiehec3315982017-06-10 01:22:09191 }
192
193 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
194 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample;
195 } else {
196 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM;
[email protected]c9bdcbd2012-07-19 23:35:54197 }
198
199 // Initialize the IAudioClient.
[email protected]37a770b02012-08-17 00:13:17200 hr = audio_client_->Initialize(
201 AUDCLNT_SHAREMODE_SHARED,
202 AUDCLNT_STREAMFLAGS_LOOPBACK,
203 (kMaxExpectedTimerLag + audio_device_period_.InMilliseconds()) *
204 k100nsPerMillisecond,
205 0,
206 wave_format_ex_,
sergeyuc5f104b2015-01-09 19:33:24207 nullptr);
[email protected]c9bdcbd2012-07-19 23:35:54208 if (FAILED(hr)) {
209 LOG(ERROR) << "Failed to initialize IAudioClient. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24210 return false;
[email protected]c9bdcbd2012-07-19 23:35:54211 }
212
213 // Get an IAudioCaptureClient.
robliao6fc41c62017-04-28 22:41:17214 hr = audio_client_->GetService(IID_PPV_ARGS(&audio_capture_client_));
[email protected]c9bdcbd2012-07-19 23:35:54215 if (FAILED(hr)) {
216 LOG(ERROR) << "Failed to get an IAudioCaptureClient. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24217 return false;
[email protected]c9bdcbd2012-07-19 23:35:54218 }
219
220 // Start the IAudioClient.
221 hr = audio_client_->Start();
222 if (FAILED(hr)) {
223 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24224 return false;
[email protected]c9bdcbd2012-07-19 23:35:54225 }
226
zijiehe26fe0da2017-05-23 04:34:11227 volume_filter_.ActivateBy(mm_device_.Get());
zijiehec3315982017-06-10 01:22:09228 volume_filter_.Initialize(sampling_rate_, wave_format_ex_->nChannels);
[email protected]881de5e2013-01-02 23:11:14229
[email protected]339abeca2012-07-20 18:28:24230 return true;
[email protected]c9bdcbd2012-07-19 23:35:54231}
232
zijieheb40182a2016-07-24 19:28:15233bool AudioCapturerWin::is_initialized() const {
234 // All Com components should be initialized / deinitialized together.
zijiehe26fe0da2017-05-23 04:34:11235 return !!audio_client_;
zijiehe3ba26c002016-03-10 20:49:24236}
237
[email protected]c9bdcbd2012-07-19 23:35:54238void AudioCapturerWin::DoCapture() {
[email protected]ca1488912012-07-27 17:19:04239 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
[email protected]c9bdcbd2012-07-19 23:35:54240 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]c9bdcbd2012-07-19 23:35:54241
zijiehe00c53fe2017-04-24 23:33:05242 if (!is_initialized() || default_device_detector_->GetAndReset()) {
zijieheb40182a2016-07-24 19:28:15243 if (!ResetAndInitialize()) {
244 // Initialization failed, we should wait for next DoCapture call.
245 return;
246 }
247 }
248
[email protected]c9bdcbd2012-07-19 23:35:54249 // Fetch all packets from the audio capture endpoint buffer.
[email protected]a21883d2013-03-16 09:14:51250 HRESULT hr = S_OK;
[email protected]c9bdcbd2012-07-19 23:35:54251 while (true) {
252 UINT32 next_packet_size;
253 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size);
[email protected]a21883d2013-03-16 09:14:51254 if (FAILED(hr))
255 break;
[email protected]c9bdcbd2012-07-19 23:35:54256
257 if (next_packet_size <= 0) {
258 return;
259 }
260
261 BYTE* data;
262 UINT32 frames;
263 DWORD flags;
sergeyuc5f104b2015-01-09 19:33:24264 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr,
265 nullptr);
[email protected]a21883d2013-03-16 09:14:51266 if (FAILED(hr))
267 break;
[email protected]c9bdcbd2012-07-19 23:35:54268
zijiehe26fe0da2017-05-23 04:34:11269 if (volume_filter_.Apply(reinterpret_cast<int16_t*>(data), frames)) {
270 std::unique_ptr<AudioPacket> packet(new AudioPacket());
271 packet->add_data(data, frames * wave_format_ex_->nBlockAlign);
272 packet->set_encoding(AudioPacket::ENCODING_RAW);
273 packet->set_sampling_rate(sampling_rate_);
274 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
zijiehec3315982017-06-10 01:22:09275 // Only the count of channels is taken into account now, we should also
276 // consider dwChannelMask.
zijiehe2fc3d052017-06-13 03:27:42277 // TODO(zijiehe): Convert dwChannelMask to layout and pass it to
278 // AudioPump. So the stream can be downmixed properly with both number and
279 // layouts of speakers.
zijiehec3315982017-06-10 01:22:09280 packet->set_channels(static_cast<AudioPacket::Channels>(
281 wave_format_ex_->nChannels));
zijiehe26fe0da2017-05-23 04:34:11282
283 callback_.Run(std::move(packet));
284 }
[email protected]c9bdcbd2012-07-19 23:35:54285
286 hr = audio_capture_client_->ReleaseBuffer(frames);
[email protected]a21883d2013-03-16 09:14:51287 if (FAILED(hr))
288 break;
289 }
290
291 // There is nothing to capture if the audio endpoint device has been unplugged
292 // or disabled.
293 if (hr == AUDCLNT_E_DEVICE_INVALIDATED)
294 return;
295
296 // Avoid reporting the same error multiple times.
297 if (FAILED(hr) && hr != last_capture_error_) {
298 last_capture_error_ = hr;
299 LOG(ERROR) << "Failed to capture an audio packet: 0x"
300 << std::hex << hr << std::dec << ".";
[email protected]c9bdcbd2012-07-19 23:35:54301 }
302}
303
[email protected]e8aaf2ca2012-09-11 18:07:24304bool AudioCapturer::IsSupported() {
305 return true;
306}
307
dcheng0765c492016-04-06 22:41:53308std::unique_ptr<AudioCapturer> AudioCapturer::Create() {
309 return base::WrapUnique(new AudioCapturerWin());
[email protected]c9bdcbd2012-07-19 23:35:54310}
311
312} // namespace remoting