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 "remoting/host/audio_capturer_win.h" | 5 #include "remoting/host/audio_capturer_win.h" |
6 | 6 |
7 #include <avrt.h> | 7 #include <avrt.h> |
8 #include <mmreg.h> | 8 #include <mmreg.h> |
9 #include <mmsystem.h> | 9 #include <mmsystem.h> |
10 #include <objbase.h> | 10 #include <objbase.h> |
(...skipping 27 matching lines...) Expand all Loading... |
38 | 38 |
39 // Upper bound for the timer precision error, in milliseconds. | 39 // Upper bound for the timer precision error, in milliseconds. |
40 // Timers are supposed to be accurate to 20ms, so we use 30ms to be safe. | 40 // Timers are supposed to be accurate to 20ms, so we use 30ms to be safe. |
41 const int kMaxExpectedTimerLag = 30; | 41 const int kMaxExpectedTimerLag = 30; |
42 } // namespace | 42 } // namespace |
43 | 43 |
44 namespace remoting { | 44 namespace remoting { |
45 | 45 |
46 AudioCapturerWin::AudioCapturerWin() | 46 AudioCapturerWin::AudioCapturerWin() |
47 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), | 47 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), |
48 silence_detector_(kSilenceThreshold), | 48 volume_filter_(kSilenceThreshold), |
49 last_capture_error_(S_OK) { | 49 last_capture_error_(S_OK) { |
50 thread_checker_.DetachFromThread(); | 50 thread_checker_.DetachFromThread(); |
51 } | 51 } |
52 | 52 |
53 AudioCapturerWin::~AudioCapturerWin() { | 53 AudioCapturerWin::~AudioCapturerWin() { |
54 DCHECK(thread_checker_.CalledOnValidThread()); | 54 DCHECK(thread_checker_.CalledOnValidThread()); |
55 Deinitialize(); | 55 Deinitialize(); |
56 } | 56 } |
57 | 57 |
58 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { | 58 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { |
(...skipping 25 matching lines...) Expand all Loading... |
84 void AudioCapturerWin::Deinitialize() { | 84 void AudioCapturerWin::Deinitialize() { |
85 DCHECK(thread_checker_.CalledOnValidThread()); | 85 DCHECK(thread_checker_.CalledOnValidThread()); |
86 wave_format_ex_.Reset(nullptr); | 86 wave_format_ex_.Reset(nullptr); |
87 default_device_detector_.reset(); | 87 default_device_detector_.reset(); |
88 audio_capture_client_.Reset(); | 88 audio_capture_client_.Reset(); |
89 if (audio_client_) { | 89 if (audio_client_) { |
90 audio_client_->Stop(); | 90 audio_client_->Stop(); |
91 } | 91 } |
92 audio_client_.Reset(); | 92 audio_client_.Reset(); |
93 mm_device_.Reset(); | 93 mm_device_.Reset(); |
94 audio_volume_.Reset(); | |
95 } | 94 } |
96 | 95 |
97 bool AudioCapturerWin::Initialize() { | 96 bool AudioCapturerWin::Initialize() { |
98 DCHECK(!audio_capture_client_.Get()); | 97 DCHECK(!audio_capture_client_.Get()); |
99 DCHECK(!audio_client_.Get()); | 98 DCHECK(!audio_client_.Get()); |
100 DCHECK(!mm_device_.Get()); | 99 DCHECK(!mm_device_.Get()); |
101 DCHECK(!audio_volume_.Get()); | |
102 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); | 100 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); |
103 DCHECK(thread_checker_.CalledOnValidThread()); | 101 DCHECK(thread_checker_.CalledOnValidThread()); |
104 | 102 |
105 HRESULT hr = S_OK; | 103 HRESULT hr = S_OK; |
106 base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator; | 104 base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator; |
107 hr = ::CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, | 105 hr = ::CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, |
108 IID_PPV_ARGS(&mm_device_enumerator)); | 106 IID_PPV_ARGS(&mm_device_enumerator)); |
109 if (FAILED(hr)) { | 107 if (FAILED(hr)) { |
110 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr; | 108 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr; |
111 return false; | 109 return false; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 return false; | 225 return false; |
228 } | 226 } |
229 | 227 |
230 // Start the IAudioClient. | 228 // Start the IAudioClient. |
231 hr = audio_client_->Start(); | 229 hr = audio_client_->Start(); |
232 if (FAILED(hr)) { | 230 if (FAILED(hr)) { |
233 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; | 231 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; |
234 return false; | 232 return false; |
235 } | 233 } |
236 | 234 |
237 // Initialize IAudioEndpointVolume. | 235 volume_filter_.ActivateBy(mm_device_.Get()); |
238 // TODO(zijiehe): Do we need to control per process volume? | 236 volume_filter_.Initialize(sampling_rate_, kChannels); |
239 hr = mm_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr, | |
240 &audio_volume_); | |
241 if (FAILED(hr)) { | |
242 LOG(ERROR) << "Failed to get an IAudioEndpointVolume. Error " << hr; | |
243 return false; | |
244 } | |
245 | |
246 silence_detector_.Reset(sampling_rate_, kChannels); | |
247 | 237 |
248 return true; | 238 return true; |
249 } | 239 } |
250 | 240 |
251 bool AudioCapturerWin::is_initialized() const { | 241 bool AudioCapturerWin::is_initialized() const { |
252 // All Com components should be initialized / deinitialized together. | 242 // All Com components should be initialized / deinitialized together. |
253 return !!audio_volume_; | 243 return !!audio_client_; |
254 } | |
255 | |
256 float AudioCapturerWin::GetAudioLevel() { | |
257 BOOL mute; | |
258 HRESULT hr = audio_volume_->GetMute(&mute); | |
259 if (FAILED(hr)) { | |
260 LOG(ERROR) << "Failed to get mute status from IAudioEndpointVolume, error " | |
261 << hr; | |
262 return 1; | |
263 } | |
264 if (mute) { | |
265 return 0; | |
266 } | |
267 | |
268 float level; | |
269 hr = audio_volume_->GetMasterVolumeLevelScalar(&level); | |
270 if (FAILED(hr) || level > 1) { | |
271 LOG(ERROR) << "Failed to get master volume from IAudioEndpointVolume, " | |
272 "error " | |
273 << hr; | |
274 return 1; | |
275 } | |
276 if (level < 0) { | |
277 return 0; | |
278 } | |
279 return level; | |
280 } | |
281 | |
282 void AudioCapturerWin::ProcessSamples(uint8_t* data, size_t frames) { | |
283 if (frames == 0) { | |
284 return; | |
285 } | |
286 | |
287 int16_t* samples = reinterpret_cast<int16_t*>(data); | |
288 static_assert(sizeof(samples[0]) == kBytesPerSample, | |
289 "expect 16 bits per sample"); | |
290 size_t sample_count = frames * kChannels; | |
291 if (silence_detector_.IsSilence(samples, sample_count)) { | |
292 return; | |
293 } | |
294 | |
295 // Windows API does not provide volume adjusted audio sample as Linux does. | |
296 // So we need to manually apply volume to the samples. | |
297 float level = GetAudioLevel(); | |
298 if (level == 0) { | |
299 return; | |
300 } | |
301 | |
302 if (level < 1) { | |
303 int32_t level_int = static_cast<int32_t>(level * 65536); | |
304 for (size_t i = 0; i < sample_count; i++) { | |
305 samples[i] = (static_cast<int32_t>(samples[i]) * level_int) >> 16; | |
306 } | |
307 } | |
308 | |
309 std::unique_ptr<AudioPacket> packet(new AudioPacket()); | |
310 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); | |
311 packet->set_encoding(AudioPacket::ENCODING_RAW); | |
312 packet->set_sampling_rate(sampling_rate_); | |
313 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); | |
314 packet->set_channels(AudioPacket::CHANNELS_STEREO); | |
315 | |
316 callback_.Run(std::move(packet)); | |
317 } | 244 } |
318 | 245 |
319 void AudioCapturerWin::DoCapture() { | 246 void AudioCapturerWin::DoCapture() { |
320 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); | 247 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); |
321 DCHECK(thread_checker_.CalledOnValidThread()); | 248 DCHECK(thread_checker_.CalledOnValidThread()); |
322 | 249 |
323 if (!is_initialized() || default_device_detector_->GetAndReset()) { | 250 if (!is_initialized() || default_device_detector_->GetAndReset()) { |
324 if (!ResetAndInitialize()) { | 251 if (!ResetAndInitialize()) { |
325 // Initialization failed, we should wait for next DoCapture call. | 252 // Initialization failed, we should wait for next DoCapture call. |
326 return; | 253 return; |
(...skipping 13 matching lines...) Expand all Loading... |
340 } | 267 } |
341 | 268 |
342 BYTE* data; | 269 BYTE* data; |
343 UINT32 frames; | 270 UINT32 frames; |
344 DWORD flags; | 271 DWORD flags; |
345 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr, | 272 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr, |
346 nullptr); | 273 nullptr); |
347 if (FAILED(hr)) | 274 if (FAILED(hr)) |
348 break; | 275 break; |
349 | 276 |
350 ProcessSamples(data, frames); | 277 if (volume_filter_.Apply(reinterpret_cast<int16_t*>(data), frames)) { |
| 278 std::unique_ptr<AudioPacket> packet(new AudioPacket()); |
| 279 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); |
| 280 packet->set_encoding(AudioPacket::ENCODING_RAW); |
| 281 packet->set_sampling_rate(sampling_rate_); |
| 282 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); |
| 283 packet->set_channels(AudioPacket::CHANNELS_STEREO); |
| 284 |
| 285 callback_.Run(std::move(packet)); |
| 286 } |
351 | 287 |
352 hr = audio_capture_client_->ReleaseBuffer(frames); | 288 hr = audio_capture_client_->ReleaseBuffer(frames); |
353 if (FAILED(hr)) | 289 if (FAILED(hr)) |
354 break; | 290 break; |
355 } | 291 } |
356 | 292 |
357 // There is nothing to capture if the audio endpoint device has been unplugged | 293 // There is nothing to capture if the audio endpoint device has been unplugged |
358 // or disabled. | 294 // or disabled. |
359 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) | 295 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) |
360 return; | 296 return; |
361 | 297 |
362 // Avoid reporting the same error multiple times. | 298 // Avoid reporting the same error multiple times. |
363 if (FAILED(hr) && hr != last_capture_error_) { | 299 if (FAILED(hr) && hr != last_capture_error_) { |
364 last_capture_error_ = hr; | 300 last_capture_error_ = hr; |
365 LOG(ERROR) << "Failed to capture an audio packet: 0x" | 301 LOG(ERROR) << "Failed to capture an audio packet: 0x" |
366 << std::hex << hr << std::dec << "."; | 302 << std::hex << hr << std::dec << "."; |
367 } | 303 } |
368 } | 304 } |
369 | 305 |
370 bool AudioCapturer::IsSupported() { | 306 bool AudioCapturer::IsSupported() { |
371 return true; | 307 return true; |
372 } | 308 } |
373 | 309 |
374 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { | 310 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { |
375 return base::WrapUnique(new AudioCapturerWin()); | 311 return base::WrapUnique(new AudioCapturerWin()); |
376 } | 312 } |
377 | 313 |
378 } // namespace remoting | 314 } // namespace remoting |
OLD | NEW |