| 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 30 matching lines...) Expand all Loading... |
| 41 | 41 |
| 42 AudioCapturerWin::AudioCapturerWin() | 42 AudioCapturerWin::AudioCapturerWin() |
| 43 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), | 43 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), |
| 44 silence_detector_(kSilenceThreshold), | 44 silence_detector_(kSilenceThreshold), |
| 45 last_capture_error_(S_OK) { | 45 last_capture_error_(S_OK) { |
| 46 thread_checker_.DetachFromThread(); | 46 thread_checker_.DetachFromThread(); |
| 47 } | 47 } |
| 48 | 48 |
| 49 AudioCapturerWin::~AudioCapturerWin() { | 49 AudioCapturerWin::~AudioCapturerWin() { |
| 50 DCHECK(thread_checker_.CalledOnValidThread()); | 50 DCHECK(thread_checker_.CalledOnValidThread()); |
| 51 if (audio_client_) { |
| 52 audio_client_->Stop(); |
| 53 } |
| 51 } | 54 } |
| 52 | 55 |
| 53 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { | 56 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { |
| 54 DCHECK(!audio_capture_client_.get()); | 57 DCHECK(!audio_capture_client_.get()); |
| 55 DCHECK(!audio_client_.get()); | 58 DCHECK(!audio_client_.get()); |
| 56 DCHECK(!mm_device_.get()); | 59 DCHECK(!mm_device_.get()); |
| 57 DCHECK(!audio_volume_.get()); | 60 DCHECK(!audio_volume_.get()); |
| 58 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); | 61 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); |
| 59 DCHECK(thread_checker_.CalledOnValidThread()); | 62 DCHECK(thread_checker_.CalledOnValidThread()); |
| 60 | 63 |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 return false; | 190 return false; |
| 188 } | 191 } |
| 189 | 192 |
| 190 // Start the IAudioClient. | 193 // Start the IAudioClient. |
| 191 hr = audio_client_->Start(); | 194 hr = audio_client_->Start(); |
| 192 if (FAILED(hr)) { | 195 if (FAILED(hr)) { |
| 193 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; | 196 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; |
| 194 return false; | 197 return false; |
| 195 } | 198 } |
| 196 | 199 |
| 197 // Initialize ISimpleAudioVolume. | 200 // Initialize IAudioEndpointVolume. |
| 198 // TODO(zijiehe): Do we need to control per process volume? | 201 // TODO(zijiehe): Do we need to control per process volume? |
| 199 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), | 202 hr = mm_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr, |
| 200 audio_volume_.ReceiveVoid()); | 203 audio_volume_.ReceiveVoid()); |
| 201 if (FAILED(hr)) { | 204 if (FAILED(hr)) { |
| 202 LOG(ERROR) << "Failed to get an ISimpleAudioVolume. Error " << hr; | 205 LOG(ERROR) << "Failed to get an IAudioEndpointVolume. Error " << hr; |
| 203 return false; | 206 return false; |
| 204 } | 207 } |
| 205 | 208 |
| 206 silence_detector_.Reset(sampling_rate_, kChannels); | 209 silence_detector_.Reset(sampling_rate_, kChannels); |
| 207 | 210 |
| 208 // Start capturing. | 211 // Start capturing. |
| 209 capture_timer_->Start(FROM_HERE, | 212 capture_timer_->Start(FROM_HERE, |
| 210 audio_device_period_, | 213 audio_device_period_, |
| 211 this, | 214 this, |
| 212 &AudioCapturerWin::DoCapture); | 215 &AudioCapturerWin::DoCapture); |
| 213 return true; | 216 return true; |
| 214 } | 217 } |
| 215 | 218 |
| 216 float AudioCapturerWin::GetAudioLevel() { | 219 float AudioCapturerWin::GetAudioLevel() { |
| 217 BOOL mute; | 220 BOOL mute; |
| 218 HRESULT hr = audio_volume_->GetMute(&mute); | 221 HRESULT hr = audio_volume_->GetMute(&mute); |
| 219 if (FAILED(hr)) { | 222 if (FAILED(hr)) { |
| 223 LOG(ERROR) << "Failed to get mute status from IAudioEndpointVolume, error " |
| 224 << hr; |
| 220 return 1; | 225 return 1; |
| 221 } | 226 } |
| 222 if (mute) { | 227 if (mute) { |
| 223 return 0; | 228 return 0; |
| 224 } | 229 } |
| 225 | 230 |
| 226 float level; | 231 float level; |
| 227 hr = audio_volume_->GetMasterVolume(&level); | 232 hr = audio_volume_->GetMasterVolumeLevelScalar(&level); |
| 228 if (FAILED(hr) || level > 1) { | 233 if (FAILED(hr) || level > 1) { |
| 234 LOG(ERROR) << "Failed to get master volume from IAudioEndpointVolume, " |
| 235 "error " |
| 236 << hr; |
| 229 return 1; | 237 return 1; |
| 230 } | 238 } |
| 231 if (level < 0) { | 239 if (level < 0) { |
| 232 return 0; | 240 return 0; |
| 233 } | 241 } |
| 234 return level; | 242 return level; |
| 235 } | 243 } |
| 236 | 244 |
| 237 void AudioCapturerWin::ProcessSamples(uint8_t* data, | 245 void AudioCapturerWin::ProcessSamples(uint8_t* data, size_t frames) { |
| 238 size_t frames, | |
| 239 int32_t flags) { | |
| 240 if (frames == 0) { | 246 if (frames == 0) { |
| 241 return; | 247 return; |
| 242 } | 248 } |
| 243 | 249 |
| 244 if ((flags & AUDCLNT_BUFFERFLAGS_SILENT) == 0) { | |
| 245 return; | |
| 246 } | |
| 247 | |
| 248 int16_t* samples = reinterpret_cast<int16_t*>(data); | 250 int16_t* samples = reinterpret_cast<int16_t*>(data); |
| 249 static_assert(sizeof(samples[0]) == kBytesPerSample, | 251 static_assert(sizeof(samples[0]) == kBytesPerSample, |
| 250 "expect 16 bits per sample"); | 252 "expect 16 bits per sample"); |
| 251 size_t sample_count = frames * kChannels; | 253 size_t sample_count = frames * kChannels; |
| 252 if (silence_detector_.IsSilence(samples, sample_count)) { | 254 if (silence_detector_.IsSilence(samples, sample_count)) { |
| 253 return; | 255 return; |
| 254 } | 256 } |
| 255 | 257 |
| 258 // Windows API does not provide volume adjusted audio sample as Linux does. |
| 259 // So we need to manually apply volume to the samples. |
| 256 float level = GetAudioLevel(); | 260 float level = GetAudioLevel(); |
| 257 if (level == 0) { | 261 if (level == 0) { |
| 258 return; | 262 return; |
| 259 } | 263 } |
| 260 | 264 |
| 261 if (level < 1) { | 265 if (level < 1) { |
| 262 // Windows API does not provide volume adjusted audio sample as Linux does. | |
| 263 // So we need to manually append volume signal to the samples. | |
| 264 int32_t level_int = static_cast<int32_t>(level * 65536); | 266 int32_t level_int = static_cast<int32_t>(level * 65536); |
| 265 for (size_t i = 0; i < sample_count; i++) { | 267 for (size_t i = 0; i < sample_count; i++) { |
| 266 samples[i] = (static_cast<int32_t>(samples[i]) * level_int) >> 16; | 268 samples[i] = (static_cast<int32_t>(samples[i]) * level_int) >> 16; |
| 267 } | 269 } |
| 268 } | 270 } |
| 269 | 271 |
| 270 scoped_ptr<AudioPacket> packet(new AudioPacket()); | 272 scoped_ptr<AudioPacket> packet(new AudioPacket()); |
| 271 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); | 273 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); |
| 272 packet->set_encoding(AudioPacket::ENCODING_RAW); | 274 packet->set_encoding(AudioPacket::ENCODING_RAW); |
| 273 packet->set_sampling_rate(sampling_rate_); | 275 packet->set_sampling_rate(sampling_rate_); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 294 } | 296 } |
| 295 | 297 |
| 296 BYTE* data; | 298 BYTE* data; |
| 297 UINT32 frames; | 299 UINT32 frames; |
| 298 DWORD flags; | 300 DWORD flags; |
| 299 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr, | 301 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr, |
| 300 nullptr); | 302 nullptr); |
| 301 if (FAILED(hr)) | 303 if (FAILED(hr)) |
| 302 break; | 304 break; |
| 303 | 305 |
| 304 ProcessSamples(data, frames, flags); | 306 ProcessSamples(data, frames); |
| 305 | 307 |
| 306 hr = audio_capture_client_->ReleaseBuffer(frames); | 308 hr = audio_capture_client_->ReleaseBuffer(frames); |
| 307 if (FAILED(hr)) | 309 if (FAILED(hr)) |
| 308 break; | 310 break; |
| 309 } | 311 } |
| 310 | 312 |
| 311 // There is nothing to capture if the audio endpoint device has been unplugged | 313 // There is nothing to capture if the audio endpoint device has been unplugged |
| 312 // or disabled. | 314 // or disabled. |
| 313 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) | 315 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) |
| 314 return; | 316 return; |
| 315 | 317 |
| 316 // Avoid reporting the same error multiple times. | 318 // Avoid reporting the same error multiple times. |
| 317 if (FAILED(hr) && hr != last_capture_error_) { | 319 if (FAILED(hr) && hr != last_capture_error_) { |
| 318 last_capture_error_ = hr; | 320 last_capture_error_ = hr; |
| 319 LOG(ERROR) << "Failed to capture an audio packet: 0x" | 321 LOG(ERROR) << "Failed to capture an audio packet: 0x" |
| 320 << std::hex << hr << std::dec << "."; | 322 << std::hex << hr << std::dec << "."; |
| 321 } | 323 } |
| 322 } | 324 } |
| 323 | 325 |
| 324 bool AudioCapturer::IsSupported() { | 326 bool AudioCapturer::IsSupported() { |
| 325 return true; | 327 return true; |
| 326 } | 328 } |
| 327 | 329 |
| 328 scoped_ptr<AudioCapturer> AudioCapturer::Create() { | 330 scoped_ptr<AudioCapturer> AudioCapturer::Create() { |
| 329 return make_scoped_ptr(new AudioCapturerWin()); | 331 return make_scoped_ptr(new AudioCapturerWin()); |
| 330 } | 332 } |
| 331 | 333 |
| 332 } // namespace remoting | 334 } // namespace remoting |
| OLD | NEW |