| 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 |