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() {
48 DCHECK(thread_checker_
.CalledOnValidThread());
51 bool AudioCapturerWin::Start(const PacketCapturedCallback
& callback
) {
52 DCHECK(!audio_capture_client_
.get());
53 DCHECK(!audio_client_
.get());
54 DCHECK(!mm_device_
.get());
55 DCHECK(static_cast<PWAVEFORMATEX
>(wave_format_ex_
) == nullptr);
56 DCHECK(thread_checker_
.CalledOnValidThread());
60 // Initialize the capture timer.
61 capture_timer_
.reset(new base::RepeatingTimer
<AudioCapturerWin
>());
65 base::win::ScopedComPtr
<IMMDeviceEnumerator
> mm_device_enumerator
;
66 hr
= mm_device_enumerator
.CreateInstance(__uuidof(MMDeviceEnumerator
));
68 LOG(ERROR
) << "Failed to create IMMDeviceEnumerator. Error " << hr
;
72 // Get the audio endpoint.
73 hr
= mm_device_enumerator
->GetDefaultAudioEndpoint(eRender
,
75 mm_device_
.Receive());
77 LOG(ERROR
) << "Failed to get IMMDevice. Error " << hr
;
81 // Get an audio client.
82 hr
= mm_device_
->Activate(__uuidof(IAudioClient
),
85 audio_client_
.ReceiveVoid());
87 LOG(ERROR
) << "Failed to get an IAudioClient. Error " << hr
;
91 REFERENCE_TIME device_period
;
92 hr
= audio_client_
->GetDevicePeriod(&device_period
, nullptr);
94 LOG(ERROR
) << "IAudioClient::GetDevicePeriod failed. Error " << hr
;
97 // We round up, if |device_period| / |k100nsPerMillisecond|
98 // is not a whole number.
99 int device_period_in_milliseconds
=
100 1 + ((device_period
- 1) / k100nsPerMillisecond
);
101 audio_device_period_
= base::TimeDelta::FromMilliseconds(
102 std::max(device_period_in_milliseconds
, kMinTimerInterval
));
104 // Get the wave format.
105 hr
= audio_client_
->GetMixFormat(&wave_format_ex_
);
107 LOG(ERROR
) << "Failed to get WAVEFORMATEX. Error " << hr
;
111 // Set the wave format
112 switch (wave_format_ex_
->wFormatTag
) {
113 case WAVE_FORMAT_IEEE_FLOAT
:
114 // Intentional fall-through.
115 case WAVE_FORMAT_PCM
:
116 if (!AudioCapturer::IsValidSampleRate(wave_format_ex_
->nSamplesPerSec
)) {
117 LOG(ERROR
) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
120 sampling_rate_
= static_cast<AudioPacket::SamplingRate
>(
121 wave_format_ex_
->nSamplesPerSec
);
123 wave_format_ex_
->wFormatTag
= WAVE_FORMAT_PCM
;
124 wave_format_ex_
->nChannels
= kChannels
;
125 wave_format_ex_
->wBitsPerSample
= kBitsPerSample
;
126 wave_format_ex_
->nBlockAlign
= kChannels
* kBytesPerSample
;
127 wave_format_ex_
->nAvgBytesPerSec
=
128 sampling_rate_
* kChannels
* kBytesPerSample
;
130 case WAVE_FORMAT_EXTENSIBLE
: {
131 PWAVEFORMATEXTENSIBLE wave_format_extensible
=
132 reinterpret_cast<WAVEFORMATEXTENSIBLE
*>(
133 static_cast<WAVEFORMATEX
*>(wave_format_ex_
));
134 if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
,
135 wave_format_extensible
->SubFormat
)) {
136 if (!AudioCapturer::IsValidSampleRate(
137 wave_format_extensible
->Format
.nSamplesPerSec
)) {
138 LOG(ERROR
) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
141 sampling_rate_
= static_cast<AudioPacket::SamplingRate
>(
142 wave_format_extensible
->Format
.nSamplesPerSec
);
144 wave_format_extensible
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
145 wave_format_extensible
->Samples
.wValidBitsPerSample
= kBitsPerSample
;
147 wave_format_extensible
->Format
.nChannels
= kChannels
;
148 wave_format_extensible
->Format
.nSamplesPerSec
= sampling_rate_
;
149 wave_format_extensible
->Format
.wBitsPerSample
= kBitsPerSample
;
150 wave_format_extensible
->Format
.nBlockAlign
=
151 kChannels
* kBytesPerSample
;
152 wave_format_extensible
->Format
.nAvgBytesPerSec
=
153 sampling_rate_
* kChannels
* kBytesPerSample
;
155 LOG(ERROR
) << "Failed to force 16-bit samples";
161 LOG(ERROR
) << "Failed to force 16-bit PCM";
165 // Initialize the IAudioClient.
166 hr
= audio_client_
->Initialize(
167 AUDCLNT_SHAREMODE_SHARED
,
168 AUDCLNT_STREAMFLAGS_LOOPBACK
,
169 (kMaxExpectedTimerLag
+ audio_device_period_
.InMilliseconds()) *
170 k100nsPerMillisecond
,
175 LOG(ERROR
) << "Failed to initialize IAudioClient. Error " << hr
;
179 // Get an IAudioCaptureClient.
180 hr
= audio_client_
->GetService(__uuidof(IAudioCaptureClient
),
181 audio_capture_client_
.ReceiveVoid());
183 LOG(ERROR
) << "Failed to get an IAudioCaptureClient. Error " << hr
;
187 // Start the IAudioClient.
188 hr
= audio_client_
->Start();
190 LOG(ERROR
) << "Failed to start IAudioClient. Error " << hr
;
194 silence_detector_
.Reset(sampling_rate_
, kChannels
);
197 capture_timer_
->Start(FROM_HERE
,
198 audio_device_period_
,
200 &AudioCapturerWin::DoCapture
);
204 void AudioCapturerWin::DoCapture() {
205 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_
));
206 DCHECK(thread_checker_
.CalledOnValidThread());
208 // Fetch all packets from the audio capture endpoint buffer.
211 UINT32 next_packet_size
;
212 HRESULT hr
= audio_capture_client_
->GetNextPacketSize(&next_packet_size
);
216 if (next_packet_size
<= 0) {
223 hr
= audio_capture_client_
->GetBuffer(&data
, &frames
, &flags
, nullptr,
228 if ((flags
& AUDCLNT_BUFFERFLAGS_SILENT
) == 0 &&
229 !silence_detector_
.IsSilence(
230 reinterpret_cast<const int16
*>(data
), frames
* kChannels
)) {
231 scoped_ptr
<AudioPacket
> packet(new AudioPacket());
232 packet
->add_data(data
, frames
* wave_format_ex_
->nBlockAlign
);
233 packet
->set_encoding(AudioPacket::ENCODING_RAW
);
234 packet
->set_sampling_rate(sampling_rate_
);
235 packet
->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2
);
236 packet
->set_channels(AudioPacket::CHANNELS_STEREO
);
238 callback_
.Run(packet
.Pass());
241 hr
= audio_capture_client_
->ReleaseBuffer(frames
);
246 // There is nothing to capture if the audio endpoint device has been unplugged
248 if (hr
== AUDCLNT_E_DEVICE_INVALIDATED
)
251 // Avoid reporting the same error multiple times.
252 if (FAILED(hr
) && hr
!= last_capture_error_
) {
253 last_capture_error_
= hr
;
254 LOG(ERROR
) << "Failed to capture an audio packet: 0x"
255 << std::hex
<< hr
<< std::dec
<< ".";
259 bool AudioCapturer::IsSupported() {
263 scoped_ptr
<AudioCapturer
> AudioCapturer::Create() {
264 return make_scoped_ptr(new AudioCapturerWin());
267 } // namespace remoting