Chromium Code Reviews| 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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 } | 47 } |
| 48 | 48 |
| 49 AudioCapturerWin::~AudioCapturerWin() { | 49 AudioCapturerWin::~AudioCapturerWin() { |
| 50 DCHECK(thread_checker_.CalledOnValidThread()); | 50 DCHECK(thread_checker_.CalledOnValidThread()); |
| 51 } | 51 } |
| 52 | 52 |
| 53 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { | 53 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { |
| 54 DCHECK(!audio_capture_client_.get()); | 54 DCHECK(!audio_capture_client_.get()); |
| 55 DCHECK(!audio_client_.get()); | 55 DCHECK(!audio_client_.get()); |
| 56 DCHECK(!mm_device_.get()); | 56 DCHECK(!mm_device_.get()); |
| 57 DCHECK(!audio_volume_.get()); | |
| 57 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); | 58 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); |
| 58 DCHECK(thread_checker_.CalledOnValidThread()); | 59 DCHECK(thread_checker_.CalledOnValidThread()); |
| 59 | 60 |
| 60 callback_ = callback; | 61 callback_ = callback; |
| 61 | 62 |
| 62 // Initialize the capture timer. | 63 // Initialize the capture timer. |
| 63 capture_timer_.reset(new base::RepeatingTimer()); | 64 capture_timer_.reset(new base::RepeatingTimer()); |
| 64 | 65 |
| 65 HRESULT hr = S_OK; | 66 HRESULT hr = S_OK; |
| 66 | 67 |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 186 return false; | 187 return false; |
| 187 } | 188 } |
| 188 | 189 |
| 189 // Start the IAudioClient. | 190 // Start the IAudioClient. |
| 190 hr = audio_client_->Start(); | 191 hr = audio_client_->Start(); |
| 191 if (FAILED(hr)) { | 192 if (FAILED(hr)) { |
| 192 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; | 193 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; |
| 193 return false; | 194 return false; |
| 194 } | 195 } |
| 195 | 196 |
| 197 // Initialize ISimpleAudioVolume. | |
| 198 // TODO(zijiehe): Do we need to control per process volume? | |
| 199 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), | |
| 200 audio_volume_.ReceiveVoid()); | |
| 201 if (FAILED(hr)) { | |
| 202 LOG(ERROR) << "Failed to get an ISimpleAudioVolume. Error " << hr; | |
| 203 return false; | |
| 204 } | |
| 205 | |
| 196 silence_detector_.Reset(sampling_rate_, kChannels); | 206 silence_detector_.Reset(sampling_rate_, kChannels); |
| 197 | 207 |
| 198 // Start capturing. | 208 // Start capturing. |
| 199 capture_timer_->Start(FROM_HERE, | 209 capture_timer_->Start(FROM_HERE, |
| 200 audio_device_period_, | 210 audio_device_period_, |
| 201 this, | 211 this, |
| 202 &AudioCapturerWin::DoCapture); | 212 &AudioCapturerWin::DoCapture); |
| 203 return true; | 213 return true; |
| 204 } | 214 } |
| 205 | 215 |
| 216 float AudioCapturerWin::GetAudioLevel() { | |
| 217 BOOL mute; | |
| 218 HRESULT hr = audio_volume_->GetMute(&mute); | |
| 219 if (FAILED(hr)) { | |
| 220 return 1; | |
| 221 } | |
| 222 if (mute) { | |
| 223 return 0; | |
| 224 } | |
| 225 | |
| 226 float level; | |
| 227 hr = audio_volume_->GetMasterVolume(&level); | |
| 228 if (FAILED(hr) || level > 1) { | |
| 229 return 1; | |
| 230 } | |
| 231 if (level < 0) { | |
| 232 return 0; | |
| 233 } | |
| 234 return level; | |
| 235 } | |
| 236 | |
| 237 void AudioCapturerWin::ProcessSamples(uint8_t* data, | |
| 238 size_t frames, | |
| 239 int32_t flags) { | |
| 240 if (frames == 0) { | |
| 241 return; | |
| 242 } | |
| 243 | |
| 244 if ((flags & AUDCLNT_BUFFERFLAGS_SILENT) == 0) { | |
| 245 return; | |
| 246 } | |
| 247 | |
| 248 float level = GetAudioLevel(); | |
| 249 if (level == 0) { | |
| 250 return; | |
| 251 } | |
| 252 | |
| 253 int16_t* samples = reinterpret_cast<int16_t*>(data); | |
| 254 static_assert(sizeof(samples[0]) == kBytesPerSample, | |
| 255 "expect 16 bits per sample"); | |
| 256 size_t sample_count = frames * kChannels; | |
| 257 if (level < 1) { | |
| 258 // Windows API does not provide volume adjusted audio sample as Linux does. | |
| 259 // So we need to manually append volume signal to the samples. | |
| 260 int32_t level_int = static_cast<int32_t>(level * 65536); | |
| 261 for (size_t i = 0; i < sample_count; i++) { | |
| 262 samples[i] = (static_cast<int32_t>(samples[i]) * level_int) >> 16; | |
| 263 } | |
| 264 } | |
| 265 if (silence_detector_.IsSilence(samples, sample_count)) { | |
|
Sergey Ulanov
2016/03/10 01:13:40
I still think this should be done before volume is
Hzj_jie
2016/03/10 01:58:59
Emm, I see your point clearly. Most of time, we wi
| |
| 266 return; | |
| 267 } | |
| 268 | |
| 269 scoped_ptr<AudioPacket> packet(new AudioPacket()); | |
| 270 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); | |
| 271 packet->set_encoding(AudioPacket::ENCODING_RAW); | |
| 272 packet->set_sampling_rate(sampling_rate_); | |
| 273 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); | |
| 274 packet->set_channels(AudioPacket::CHANNELS_STEREO); | |
| 275 | |
| 276 callback_.Run(std::move(packet)); | |
| 277 } | |
| 278 | |
| 206 void AudioCapturerWin::DoCapture() { | 279 void AudioCapturerWin::DoCapture() { |
| 207 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); | 280 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); |
| 208 DCHECK(thread_checker_.CalledOnValidThread()); | 281 DCHECK(thread_checker_.CalledOnValidThread()); |
| 209 | 282 |
| 210 // Fetch all packets from the audio capture endpoint buffer. | 283 // Fetch all packets from the audio capture endpoint buffer. |
| 211 HRESULT hr = S_OK; | 284 HRESULT hr = S_OK; |
| 212 while (true) { | 285 while (true) { |
| 213 UINT32 next_packet_size; | 286 UINT32 next_packet_size; |
| 214 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size); | 287 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size); |
| 215 if (FAILED(hr)) | 288 if (FAILED(hr)) |
| 216 break; | 289 break; |
| 217 | 290 |
| 218 if (next_packet_size <= 0) { | 291 if (next_packet_size <= 0) { |
| 219 return; | 292 return; |
| 220 } | 293 } |
| 221 | 294 |
| 222 BYTE* data; | 295 BYTE* data; |
| 223 UINT32 frames; | 296 UINT32 frames; |
| 224 DWORD flags; | 297 DWORD flags; |
| 225 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr, | 298 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr, |
| 226 nullptr); | 299 nullptr); |
| 227 if (FAILED(hr)) | 300 if (FAILED(hr)) |
| 228 break; | 301 break; |
| 229 | 302 |
| 230 if ((flags & AUDCLNT_BUFFERFLAGS_SILENT) == 0 && | 303 ProcessSamples(data, frames, flags); |
| 231 !silence_detector_.IsSilence(reinterpret_cast<const int16_t*>(data), | |
| 232 frames * kChannels)) { | |
| 233 scoped_ptr<AudioPacket> packet(new AudioPacket()); | |
| 234 packet->add_data(data, frames * wave_format_ex_->nBlockAlign); | |
| 235 packet->set_encoding(AudioPacket::ENCODING_RAW); | |
| 236 packet->set_sampling_rate(sampling_rate_); | |
| 237 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); | |
| 238 packet->set_channels(AudioPacket::CHANNELS_STEREO); | |
| 239 | |
| 240 callback_.Run(std::move(packet)); | |
| 241 } | |
| 242 | 304 |
| 243 hr = audio_capture_client_->ReleaseBuffer(frames); | 305 hr = audio_capture_client_->ReleaseBuffer(frames); |
| 244 if (FAILED(hr)) | 306 if (FAILED(hr)) |
| 245 break; | 307 break; |
| 246 } | 308 } |
| 247 | 309 |
| 248 // There is nothing to capture if the audio endpoint device has been unplugged | 310 // There is nothing to capture if the audio endpoint device has been unplugged |
| 249 // or disabled. | 311 // or disabled. |
| 250 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) | 312 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) |
| 251 return; | 313 return; |
| 252 | 314 |
| 253 // Avoid reporting the same error multiple times. | 315 // Avoid reporting the same error multiple times. |
| 254 if (FAILED(hr) && hr != last_capture_error_) { | 316 if (FAILED(hr) && hr != last_capture_error_) { |
| 255 last_capture_error_ = hr; | 317 last_capture_error_ = hr; |
| 256 LOG(ERROR) << "Failed to capture an audio packet: 0x" | 318 LOG(ERROR) << "Failed to capture an audio packet: 0x" |
| 257 << std::hex << hr << std::dec << "."; | 319 << std::hex << hr << std::dec << "."; |
| 258 } | 320 } |
| 259 } | 321 } |
| 260 | 322 |
| 261 bool AudioCapturer::IsSupported() { | 323 bool AudioCapturer::IsSupported() { |
| 262 return true; | 324 return true; |
| 263 } | 325 } |
| 264 | 326 |
| 265 scoped_ptr<AudioCapturer> AudioCapturer::Create() { | 327 scoped_ptr<AudioCapturer> AudioCapturer::Create() { |
| 266 return make_scoped_ptr(new AudioCapturerWin()); | 328 return make_scoped_ptr(new AudioCapturerWin()); |
| 267 } | 329 } |
| 268 | 330 |
| 269 } // namespace remoting | 331 } // namespace remoting |
| OLD | NEW |