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