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