blob: 3fc768b787a76a3ffcf19bca5b80d7310742a2a4 [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 <windows.h>
[email protected]c9bdcbd2012-07-19 23:35:548#include <avrt.h>
[email protected]c9bdcbd2012-07-19 23:35:549#include <mmreg.h>
10#include <mmsystem.h>
11
[email protected]37a770b02012-08-17 00:13:1712#include <algorithm>
[email protected]07cb35f2012-07-31 23:10:1013#include <stdlib.h>
14
[email protected]c9bdcbd2012-07-19 23:35:5415#include "base/logging.h"
[email protected]c9bdcbd2012-07-19 23:35:5416
17namespace {
18const int kChannels = 2;
[email protected]881de5e2013-01-02 23:11:1419const int kBytesPerSample = 2;
20const int kBitsPerSample = kBytesPerSample * 8;
[email protected]c9bdcbd2012-07-19 23:35:5421// Conversion factor from 100ns to 1ms.
[email protected]37a770b02012-08-17 00:13:1722const int k100nsPerMillisecond = 10000;
[email protected]07cb35f2012-07-31 23:10:1023
24// Tolerance for catching packets of silence. If all samples have absolute
25// value less than this threshold, the packet will be counted as a packet of
26// silence. A value of 2 was chosen, because Windows can give samples of 1 and
27// -1, even when no audio is playing.
28const int kSilenceThreshold = 2;
[email protected]37a770b02012-08-17 00:13:1729
30// Lower bound for timer intervals, in milliseconds.
31const int kMinTimerInterval = 30;
32
33// Upper bound for the timer precision error, in milliseconds.
34// Timers are supposed to be accurate to 20ms, so we use 30ms to be safe.
35const int kMaxExpectedTimerLag = 30;
[email protected]c9bdcbd2012-07-19 23:35:5436} // namespace
37
38namespace remoting {
39
[email protected]ca1488912012-07-27 17:19:0440AudioCapturerWin::AudioCapturerWin()
[email protected]881de5e2013-01-02 23:11:1441 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
[email protected]a21883d2013-03-16 09:14:5142 silence_detector_(kSilenceThreshold),
43 last_capture_error_(S_OK) {
44 thread_checker_.DetachFromThread();
[email protected]c9bdcbd2012-07-19 23:35:5445}
46
47AudioCapturerWin::~AudioCapturerWin() {
48}
49
[email protected]339abeca2012-07-20 18:28:2450bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
[email protected]c9bdcbd2012-07-19 23:35:5451 DCHECK(!audio_capture_client_.get());
52 DCHECK(!audio_client_.get());
53 DCHECK(!mm_device_.get());
54 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == NULL);
55 DCHECK(thread_checker_.CalledOnValidThread());
56
57 callback_ = callback;
58
59 // Initialize the capture timer.
60 capture_timer_.reset(new base::RepeatingTimer<AudioCapturerWin>());
61
62 HRESULT hr = S_OK;
[email protected]c9bdcbd2012-07-19 23:35:5463
64 base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator;
65 hr = mm_device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator));
66 if (FAILED(hr)) {
67 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr;
[email protected]339abeca2012-07-20 18:28:2468 return false;
[email protected]c9bdcbd2012-07-19 23:35:5469 }
70
71 // Get the audio endpoint.
72 hr = mm_device_enumerator->GetDefaultAudioEndpoint(eRender,
73 eConsole,
74 mm_device_.Receive());
75 if (FAILED(hr)) {
76 LOG(ERROR) << "Failed to get IMMDevice. Error " << hr;
[email protected]339abeca2012-07-20 18:28:2477 return false;
[email protected]c9bdcbd2012-07-19 23:35:5478 }
79
80 // Get an audio client.
81 hr = mm_device_->Activate(__uuidof(IAudioClient),
82 CLSCTX_ALL,
83 NULL,
84 audio_client_.ReceiveVoid());
85 if (FAILED(hr)) {
86 LOG(ERROR) << "Failed to get an IAudioClient. Error " << hr;
[email protected]339abeca2012-07-20 18:28:2487 return false;
[email protected]c9bdcbd2012-07-19 23:35:5488 }
89
90 REFERENCE_TIME device_period;
91 hr = audio_client_->GetDevicePeriod(&device_period, NULL);
92 if (FAILED(hr)) {
93 LOG(ERROR) << "IAudioClient::GetDevicePeriod failed. Error " << hr;
[email protected]339abeca2012-07-20 18:28:2494 return false;
[email protected]c9bdcbd2012-07-19 23:35:5495 }
[email protected]37a770b02012-08-17 00:13:1796 // We round up, if |device_period| / |k100nsPerMillisecond|
97 // is not a whole number.
98 int device_period_in_milliseconds =
99 1 + ((device_period - 1) / k100nsPerMillisecond);
[email protected]c9bdcbd2012-07-19 23:35:54100 audio_device_period_ = base::TimeDelta::FromMilliseconds(
[email protected]37a770b02012-08-17 00:13:17101 std::max(device_period_in_milliseconds, kMinTimerInterval));
[email protected]c9bdcbd2012-07-19 23:35:54102
103 // Get the wave format.
104 hr = audio_client_->GetMixFormat(&wave_format_ex_);
105 if (FAILED(hr)) {
106 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24107 return false;
[email protected]c9bdcbd2012-07-19 23:35:54108 }
109
110 // Set the wave format
111 switch (wave_format_ex_->wFormatTag) {
112 case WAVE_FORMAT_IEEE_FLOAT:
113 // Intentional fall-through.
114 case WAVE_FORMAT_PCM:
[email protected]ca1488912012-07-27 17:19:04115 if (!AudioCapturer::IsValidSampleRate(wave_format_ex_->nSamplesPerSec)) {
116 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
117 return false;
118 }
119 sampling_rate_ = static_cast<AudioPacket::SamplingRate>(
120 wave_format_ex_->nSamplesPerSec);
121
[email protected]c9bdcbd2012-07-19 23:35:54122 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM;
123 wave_format_ex_->nChannels = kChannels;
[email protected]c9bdcbd2012-07-19 23:35:54124 wave_format_ex_->wBitsPerSample = kBitsPerSample;
[email protected]881de5e2013-01-02 23:11:14125 wave_format_ex_->nBlockAlign = kChannels * kBytesPerSample;
[email protected]c9bdcbd2012-07-19 23:35:54126 wave_format_ex_->nAvgBytesPerSec =
[email protected]881de5e2013-01-02 23:11:14127 sampling_rate_ * kChannels * kBytesPerSample;
[email protected]c9bdcbd2012-07-19 23:35:54128 break;
129 case WAVE_FORMAT_EXTENSIBLE: {
130 PWAVEFORMATEXTENSIBLE wave_format_extensible =
131 reinterpret_cast<WAVEFORMATEXTENSIBLE*>(
132 static_cast<WAVEFORMATEX*>(wave_format_ex_));
133 if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
134 wave_format_extensible->SubFormat)) {
[email protected]ca1488912012-07-27 17:19:04135 if (!AudioCapturer::IsValidSampleRate(
136 wave_format_extensible->Format.nSamplesPerSec)) {
137 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
138 return false;
139 }
140 sampling_rate_ = static_cast<AudioPacket::SamplingRate>(
141 wave_format_extensible->Format.nSamplesPerSec);
142
[email protected]c9bdcbd2012-07-19 23:35:54143 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
144 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample;
145
146 wave_format_extensible->Format.nChannels = kChannels;
[email protected]ca1488912012-07-27 17:19:04147 wave_format_extensible->Format.nSamplesPerSec = sampling_rate_;
[email protected]c9bdcbd2012-07-19 23:35:54148 wave_format_extensible->Format.wBitsPerSample = kBitsPerSample;
149 wave_format_extensible->Format.nBlockAlign =
[email protected]881de5e2013-01-02 23:11:14150 kChannels * kBytesPerSample;
[email protected]c9bdcbd2012-07-19 23:35:54151 wave_format_extensible->Format.nAvgBytesPerSec =
[email protected]881de5e2013-01-02 23:11:14152 sampling_rate_ * kChannels * kBytesPerSample;
[email protected]c9bdcbd2012-07-19 23:35:54153 } else {
154 LOG(ERROR) << "Failed to force 16-bit samples";
[email protected]339abeca2012-07-20 18:28:24155 return false;
[email protected]c9bdcbd2012-07-19 23:35:54156 }
157 break;
158 }
159 default:
[email protected]ca1488912012-07-27 17:19:04160 LOG(ERROR) << "Failed to force 16-bit PCM";
[email protected]339abeca2012-07-20 18:28:24161 return false;
[email protected]c9bdcbd2012-07-19 23:35:54162 }
163
164 // Initialize the IAudioClient.
[email protected]37a770b02012-08-17 00:13:17165 hr = audio_client_->Initialize(
166 AUDCLNT_SHAREMODE_SHARED,
167 AUDCLNT_STREAMFLAGS_LOOPBACK,
168 (kMaxExpectedTimerLag + audio_device_period_.InMilliseconds()) *
169 k100nsPerMillisecond,
170 0,
171 wave_format_ex_,
172 NULL);
[email protected]c9bdcbd2012-07-19 23:35:54173 if (FAILED(hr)) {
174 LOG(ERROR) << "Failed to initialize IAudioClient. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24175 return false;
[email protected]c9bdcbd2012-07-19 23:35:54176 }
177
178 // Get an IAudioCaptureClient.
179 hr = audio_client_->GetService(__uuidof(IAudioCaptureClient),
180 audio_capture_client_.ReceiveVoid());
181 if (FAILED(hr)) {
182 LOG(ERROR) << "Failed to get an IAudioCaptureClient. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24183 return false;
[email protected]c9bdcbd2012-07-19 23:35:54184 }
185
186 // Start the IAudioClient.
187 hr = audio_client_->Start();
188 if (FAILED(hr)) {
189 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr;
[email protected]339abeca2012-07-20 18:28:24190 return false;
[email protected]c9bdcbd2012-07-19 23:35:54191 }
192
[email protected]881de5e2013-01-02 23:11:14193 silence_detector_.Reset(sampling_rate_, kChannels);
194
[email protected]c9bdcbd2012-07-19 23:35:54195 // Start capturing.
196 capture_timer_->Start(FROM_HERE,
197 audio_device_period_,
198 this,
199 &AudioCapturerWin::DoCapture);
[email protected]339abeca2012-07-20 18:28:24200 return true;
[email protected]c9bdcbd2012-07-19 23:35:54201}
202
203void AudioCapturerWin::Stop() {
204 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]e8aaf2ca2012-09-11 18:07:24205 DCHECK(IsStarted());
[email protected]c9bdcbd2012-07-19 23:35:54206
207 capture_timer_.reset();
208 mm_device_.Release();
209 audio_client_.Release();
210 audio_capture_client_.Release();
211 wave_format_ex_.Reset(NULL);
[email protected]c9bdcbd2012-07-19 23:35:54212
213 thread_checker_.DetachFromThread();
214}
215
[email protected]e8aaf2ca2012-09-11 18:07:24216bool AudioCapturerWin::IsStarted() {
[email protected]c9bdcbd2012-07-19 23:35:54217 DCHECK(thread_checker_.CalledOnValidThread());
218 return capture_timer_.get() != NULL;
219}
220
221void AudioCapturerWin::DoCapture() {
[email protected]ca1488912012-07-27 17:19:04222 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
[email protected]c9bdcbd2012-07-19 23:35:54223 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]e8aaf2ca2012-09-11 18:07:24224 DCHECK(IsStarted());
[email protected]c9bdcbd2012-07-19 23:35:54225
226 // Fetch all packets from the audio capture endpoint buffer.
[email protected]a21883d2013-03-16 09:14:51227 HRESULT hr = S_OK;
[email protected]c9bdcbd2012-07-19 23:35:54228 while (true) {
229 UINT32 next_packet_size;
230 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size);
[email protected]a21883d2013-03-16 09:14:51231 if (FAILED(hr))
232 break;
[email protected]c9bdcbd2012-07-19 23:35:54233
234 if (next_packet_size <= 0) {
235 return;
236 }
237
238 BYTE* data;
239 UINT32 frames;
240 DWORD flags;
[email protected]881de5e2013-01-02 23:11:14241 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, NULL, NULL);
[email protected]a21883d2013-03-16 09:14:51242 if (FAILED(hr))
243 break;
[email protected]c9bdcbd2012-07-19 23:35:54244
[email protected]881de5e2013-01-02 23:11:14245 if (!silence_detector_.IsSilence(
246 reinterpret_cast<const int16*>(data), frames * kChannels)) {
[email protected]a88e2db2012-08-16 01:59:49247 scoped_ptr<AudioPacket> packet =
248 scoped_ptr<AudioPacket>(new AudioPacket());
249 packet->add_data(data, frames * wave_format_ex_->nBlockAlign);
[email protected]a88e2db2012-08-16 01:59:49250 packet->set_encoding(AudioPacket::ENCODING_RAW);
[email protected]922ecc32012-08-21 16:42:30251 packet->set_sampling_rate(sampling_rate_);
252 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
253 packet->set_channels(AudioPacket::CHANNELS_STEREO);
[email protected]c9bdcbd2012-07-19 23:35:54254
[email protected]07cb35f2012-07-31 23:10:10255 callback_.Run(packet.Pass());
[email protected]a88e2db2012-08-16 01:59:49256 }
[email protected]c9bdcbd2012-07-19 23:35:54257
258 hr = audio_capture_client_->ReleaseBuffer(frames);
[email protected]a21883d2013-03-16 09:14:51259 if (FAILED(hr))
260 break;
261 }
262
263 // There is nothing to capture if the audio endpoint device has been unplugged
264 // or disabled.
265 if (hr == AUDCLNT_E_DEVICE_INVALIDATED)
266 return;
267
268 // Avoid reporting the same error multiple times.
269 if (FAILED(hr) && hr != last_capture_error_) {
270 last_capture_error_ = hr;
271 LOG(ERROR) << "Failed to capture an audio packet: 0x"
272 << std::hex << hr << std::dec << ".";
[email protected]c9bdcbd2012-07-19 23:35:54273 }
274}
275
[email protected]e8aaf2ca2012-09-11 18:07:24276bool AudioCapturer::IsSupported() {
277 return true;
278}
279
[email protected]c9bdcbd2012-07-19 23:35:54280scoped_ptr<AudioCapturer> AudioCapturer::Create() {
281 return scoped_ptr<AudioCapturer>(new AudioCapturerWin());
282}
283
284} // namespace remoting