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
3 // found in the LICENSE file.
5 #include "remoting/host/audio_capturer_win.h"
15 #include "base/logging.h"
18 const int kChannels
= 2;
19 const int kBytesPerSample
= 2;
20 const int kBitsPerSample
= kBytesPerSample
* 8;
21 // Conversion factor from 100ns to 1ms.
22 const int k100nsPerMillisecond
= 10000;
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.
28 const int kSilenceThreshold
= 2;
30 // Lower bound for timer intervals, in milliseconds.
31 const int kMinTimerInterval
= 30;
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.
35 const int kMaxExpectedTimerLag
= 30;
40 AudioCapturerWin::AudioCapturerWin()
41 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID
),
42 silence_detector_(kSilenceThreshold
),
43 last_capture_error_(S_OK
) {
44 thread_checker_
.DetachFromThread();
47 AudioCapturerWin::~AudioCapturerWin() {
50 bool AudioCapturerWin::Start(const PacketCapturedCallback
& callback
) {
51 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());
59 // Initialize the capture timer.
60 capture_timer_
.reset(new base::RepeatingTimer
<AudioCapturerWin
>());
64 base::win::ScopedComPtr
<IMMDeviceEnumerator
> mm_device_enumerator
;
65 hr
= mm_device_enumerator
.CreateInstance(__uuidof(MMDeviceEnumerator
));
67 LOG(ERROR
) << "Failed to create IMMDeviceEnumerator. Error " << hr
;
71 // Get the audio endpoint.
72 hr
= mm_device_enumerator
->GetDefaultAudioEndpoint(eRender
,
74 mm_device_
.Receive());
76 LOG(ERROR
) << "Failed to get IMMDevice. Error " << hr
;
80 // Get an audio client.
81 hr
= mm_device_
->Activate(__uuidof(IAudioClient
),
84 audio_client_
.ReceiveVoid());
86 LOG(ERROR
) << "Failed to get an IAudioClient. Error " << hr
;
90 REFERENCE_TIME device_period
;
91 hr
= audio_client_
->GetDevicePeriod(&device_period
, NULL
);
93 LOG(ERROR
) << "IAudioClient::GetDevicePeriod failed. Error " << hr
;
96 // 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
);
100 audio_device_period_
= base::TimeDelta::FromMilliseconds(
101 std::max(device_period_in_milliseconds
, kMinTimerInterval
));
103 // Get the wave format.
104 hr
= audio_client_
->GetMixFormat(&wave_format_ex_
);
106 LOG(ERROR
) << "Failed to get WAVEFORMATEX. Error " << hr
;
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
:
115 if (!AudioCapturer::IsValidSampleRate(wave_format_ex_
->nSamplesPerSec
)) {
116 LOG(ERROR
) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
119 sampling_rate_
= static_cast<AudioPacket::SamplingRate
>(
120 wave_format_ex_
->nSamplesPerSec
);
122 wave_format_ex_
->wFormatTag
= WAVE_FORMAT_PCM
;
123 wave_format_ex_
->nChannels
= kChannels
;
124 wave_format_ex_
->wBitsPerSample
= kBitsPerSample
;
125 wave_format_ex_
->nBlockAlign
= kChannels
* kBytesPerSample
;
126 wave_format_ex_
->nAvgBytesPerSec
=
127 sampling_rate_
* kChannels
* kBytesPerSample
;
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
)) {
135 if (!AudioCapturer::IsValidSampleRate(
136 wave_format_extensible
->Format
.nSamplesPerSec
)) {
137 LOG(ERROR
) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
140 sampling_rate_
= static_cast<AudioPacket::SamplingRate
>(
141 wave_format_extensible
->Format
.nSamplesPerSec
);
143 wave_format_extensible
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
144 wave_format_extensible
->Samples
.wValidBitsPerSample
= kBitsPerSample
;
146 wave_format_extensible
->Format
.nChannels
= kChannels
;
147 wave_format_extensible
->Format
.nSamplesPerSec
= sampling_rate_
;
148 wave_format_extensible
->Format
.wBitsPerSample
= kBitsPerSample
;
149 wave_format_extensible
->Format
.nBlockAlign
=
150 kChannels
* kBytesPerSample
;
151 wave_format_extensible
->Format
.nAvgBytesPerSec
=
152 sampling_rate_
* kChannels
* kBytesPerSample
;
154 LOG(ERROR
) << "Failed to force 16-bit samples";
160 LOG(ERROR
) << "Failed to force 16-bit PCM";
164 // Initialize the IAudioClient.
165 hr
= audio_client_
->Initialize(
166 AUDCLNT_SHAREMODE_SHARED
,
167 AUDCLNT_STREAMFLAGS_LOOPBACK
,
168 (kMaxExpectedTimerLag
+ audio_device_period_
.InMilliseconds()) *
169 k100nsPerMillisecond
,
174 LOG(ERROR
) << "Failed to initialize IAudioClient. Error " << hr
;
178 // Get an IAudioCaptureClient.
179 hr
= audio_client_
->GetService(__uuidof(IAudioCaptureClient
),
180 audio_capture_client_
.ReceiveVoid());
182 LOG(ERROR
) << "Failed to get an IAudioCaptureClient. Error " << hr
;
186 // Start the IAudioClient.
187 hr
= audio_client_
->Start();
189 LOG(ERROR
) << "Failed to start IAudioClient. Error " << hr
;
193 silence_detector_
.Reset(sampling_rate_
, kChannels
);
196 capture_timer_
->Start(FROM_HERE
,
197 audio_device_period_
,
199 &AudioCapturerWin::DoCapture
);
203 void AudioCapturerWin::Stop() {
204 DCHECK(thread_checker_
.CalledOnValidThread());
207 capture_timer_
.reset();
208 mm_device_
.Release();
209 audio_client_
.Release();
210 audio_capture_client_
.Release();
211 wave_format_ex_
.Reset(NULL
);
213 thread_checker_
.DetachFromThread();
216 bool AudioCapturerWin::IsStarted() {
217 DCHECK(thread_checker_
.CalledOnValidThread());
218 return capture_timer_
.get() != NULL
;
221 void AudioCapturerWin::DoCapture() {
222 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_
));
223 DCHECK(thread_checker_
.CalledOnValidThread());
226 // Fetch all packets from the audio capture endpoint buffer.
229 UINT32 next_packet_size
;
230 HRESULT hr
= audio_capture_client_
->GetNextPacketSize(&next_packet_size
);
234 if (next_packet_size
<= 0) {
241 hr
= audio_capture_client_
->GetBuffer(&data
, &frames
, &flags
, NULL
, NULL
);
245 if ((flags
& AUDCLNT_BUFFERFLAGS_SILENT
) == 0 &&
246 !silence_detector_
.IsSilence(
247 reinterpret_cast<const int16
*>(data
), frames
* kChannels
)) {
248 scoped_ptr
<AudioPacket
> packet
=
249 scoped_ptr
<AudioPacket
>(new AudioPacket());
250 packet
->add_data(data
, frames
* wave_format_ex_
->nBlockAlign
);
251 packet
->set_encoding(AudioPacket::ENCODING_RAW
);
252 packet
->set_sampling_rate(sampling_rate_
);
253 packet
->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2
);
254 packet
->set_channels(AudioPacket::CHANNELS_STEREO
);
256 callback_
.Run(packet
.Pass());
259 hr
= audio_capture_client_
->ReleaseBuffer(frames
);
264 // There is nothing to capture if the audio endpoint device has been unplugged
266 if (hr
== AUDCLNT_E_DEVICE_INVALIDATED
)
269 // Avoid reporting the same error multiple times.
270 if (FAILED(hr
) && hr
!= last_capture_error_
) {
271 last_capture_error_
= hr
;
272 LOG(ERROR
) << "Failed to capture an audio packet: 0x"
273 << std::hex
<< hr
<< std::dec
<< ".";
277 bool AudioCapturer::IsSupported() {
281 scoped_ptr
<AudioCapturer
> AudioCapturer::Create() {
282 return scoped_ptr
<AudioCapturer
>(new AudioCapturerWin());
285 } // namespace remoting