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 "media/audio/win/audio_low_latency_input_win.h" | 5 #include "media/audio/win/audio_low_latency_input_win.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "media/audio/audio_util.h" | 10 #include "media/audio/audio_util.h" |
| 11 #include "media/audio/win/audio_manager_win.h" | 11 #include "media/audio/win/audio_manager_win.h" |
| 12 #include "media/audio/win/avrt_wrapper_win.h" | 12 #include "media/audio/win/avrt_wrapper_win.h" |
| 13 | 13 |
| 14 static const int kMinIntervalBetweenVolumeUpdatesMs = 1000; | |
| 15 | |
| 14 using base::win::ScopedComPtr; | 16 using base::win::ScopedComPtr; |
| 15 using base::win::ScopedCOMInitializer; | 17 using base::win::ScopedCOMInitializer; |
| 16 | 18 |
| 17 WASAPIAudioInputStream::WASAPIAudioInputStream( | 19 WASAPIAudioInputStream::WASAPIAudioInputStream( |
| 18 AudioManagerWin* manager, const AudioParameters& params, | 20 AudioManagerWin* manager, const AudioParameters& params, |
| 19 const std::string& device_id) | 21 const std::string& device_id) |
| 20 : com_init_(ScopedCOMInitializer::kMTA), | 22 : com_init_(ScopedCOMInitializer::kMTA), |
| 21 manager_(manager), | 23 manager_(manager), |
| 22 capture_thread_(NULL), | 24 capture_thread_(NULL), |
| 23 opened_(false), | 25 opened_(false), |
| 24 started_(false), | 26 started_(false), |
| 25 endpoint_buffer_size_frames_(0), | 27 endpoint_buffer_size_frames_(0), |
| 26 device_id_(device_id), | 28 device_id_(device_id), |
| 27 sink_(NULL) { | 29 sink_(NULL), |
| 30 volume_(0.0), | |
| 31 agc_is_enabled_(0) { | |
| 28 DCHECK(manager_); | 32 DCHECK(manager_); |
| 29 | 33 |
| 30 // Load the Avrt DLL if not already loaded. Required to support MMCSS. | 34 // Load the Avrt DLL if not already loaded. Required to support MMCSS. |
| 31 bool avrt_init = avrt::Initialize(); | 35 bool avrt_init = avrt::Initialize(); |
| 32 DCHECK(avrt_init) << "Failed to load the Avrt.dll"; | 36 DCHECK(avrt_init) << "Failed to load the Avrt.dll"; |
| 33 | 37 |
| 34 // Set up the desired capture format specified by the client. | 38 // Set up the desired capture format specified by the client. |
| 35 format_.nSamplesPerSec = params.sample_rate; | 39 format_.nSamplesPerSec = params.sample_rate; |
| 36 format_.wFormatTag = WAVE_FORMAT_PCM; | 40 format_.wFormatTag = WAVE_FORMAT_PCM; |
| 37 format_.wBitsPerSample = params.bits_per_sample; | 41 format_.wBitsPerSample = params.bits_per_sample; |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; | 189 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; |
| 186 if (!opened_) | 190 if (!opened_) |
| 187 return 0.0; | 191 return 0.0; |
| 188 | 192 |
| 189 // The effective volume value is always in the range 0.0 to 1.0, hence | 193 // The effective volume value is always in the range 0.0 to 1.0, hence |
| 190 // we can return a fixed value (=1.0) here. | 194 // we can return a fixed value (=1.0) here. |
| 191 return 1.0; | 195 return 1.0; |
| 192 } | 196 } |
| 193 | 197 |
| 194 void WASAPIAudioInputStream::SetVolume(double volume) { | 198 void WASAPIAudioInputStream::SetVolume(double volume) { |
| 199 DVLOG(1) << "SetVolume(volume=" << volume << ")"; | |
| 195 DCHECK(CalledOnValidThread()); | 200 DCHECK(CalledOnValidThread()); |
| 196 DCHECK(volume <= 1.0 && volume >= 0.0); | 201 DCHECK(volume <= 1.0 && volume >= 0.0); |
| 197 | 202 |
| 198 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; | 203 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; |
| 199 if (!opened_) | 204 if (!opened_) |
| 200 return; | 205 return; |
| 201 | 206 |
| 202 // Set a new master volume level. Valid volume levels are in the range | 207 // Set a new master volume level. Valid volume levels are in the range |
| 203 // 0.0 to 1.0. Ignore volume-change events. | 208 // 0.0 to 1.0. Ignore volume-change events. |
| 204 HRESULT hr = simple_audio_volume_->SetMasterVolume(static_cast<float>(volume), | 209 HRESULT hr = simple_audio_volume_->SetMasterVolume(static_cast<float>(volume), |
| 205 NULL); | 210 NULL); |
|
tommi (sloooow) - chröme
2012/03/16 13:31:05
indent
henrika (OOO until Aug 14)
2012/03/21 10:16:04
Done.
| |
| 206 DLOG_IF(WARNING, FAILED(hr)) << "Failed to set new input master volume."; | 211 DLOG_IF(WARNING, FAILED(hr)) << "Failed to set new input master volume."; |
| 212 | |
| 213 // We take new volume samples once every second when the AGC is enabled. | |
| 214 // To ensure that a new setting has an immediate effect, the new volume | |
| 215 // setting is cached here. It will ensure that the next OnData() callback | |
| 216 // will contain a new valid volume level. If this approach was not taken, | |
| 217 // we could report invalid volume levels to the client for a time period | |
| 218 // of up to one second. | |
| 219 if (GetAutomaticGainControl()) { | |
| 220 volume_ = GetVolume(); | |
| 221 } | |
| 207 } | 222 } |
| 208 | 223 |
| 209 double WASAPIAudioInputStream::GetVolume() { | 224 double WASAPIAudioInputStream::GetVolume() { |
| 210 DCHECK(CalledOnValidThread()); | 225 DCHECK(CalledOnValidThread()); |
| 211 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; | 226 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; |
| 212 if (!opened_) | 227 if (!opened_) |
| 213 return 0.0; | 228 return 0.0; |
| 214 | 229 |
| 215 // Retrieve the current volume level. The value is in the range 0.0 to 1.0. | 230 // Retrieve the current volume level. The value is in the range 0.0 to 1.0. |
| 216 float level = 0.0f; | 231 float level = 0.0f; |
| 217 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level); | 232 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level); |
| 218 DLOG_IF(WARNING, FAILED(hr)) << "Failed to get input master volume."; | 233 DLOG_IF(WARNING, FAILED(hr)) << "Failed to get input master volume."; |
| 219 | 234 |
| 220 return static_cast<double>(level); | 235 return static_cast<double>(level); |
| 221 } | 236 } |
| 222 | 237 |
| 238 void WASAPIAudioInputStream::SetAutomaticGainControl(bool enabled) { | |
|
tommi (sloooow) - chröme
2012/03/16 13:31:05
seems like we have a lot of similar or exactly the
henrika (OOO until Aug 14)
2012/03/21 10:16:04
I feel the same way. Let me try to come up with so
| |
| 239 base::subtle::Release_Store(&agc_is_enabled_, enabled); | |
| 240 } | |
| 241 | |
| 242 bool WASAPIAudioInputStream::GetAutomaticGainControl() { | |
| 243 return (base::subtle::Acquire_Load(&agc_is_enabled_) == 1); | |
| 244 } | |
| 245 | |
| 223 // static | 246 // static |
| 224 double WASAPIAudioInputStream::HardwareSampleRate( | 247 double WASAPIAudioInputStream::HardwareSampleRate( |
| 225 const std::string& device_id) { | 248 const std::string& device_id) { |
| 226 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format; | 249 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format; |
| 227 HRESULT hr = GetMixFormat(device_id, &audio_engine_mix_format); | 250 HRESULT hr = GetMixFormat(device_id, &audio_engine_mix_format); |
| 228 if (FAILED(hr)) | 251 if (FAILED(hr)) |
| 229 return 0.0; | 252 return 0.0; |
| 230 | 253 |
| 231 return static_cast<double>(audio_engine_mix_format->nSamplesPerSec); | 254 return static_cast<double>(audio_engine_mix_format->nSamplesPerSec); |
| 232 } | 255 } |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 // Derive a delay estimate for the captured audio packet. | 405 // Derive a delay estimate for the captured audio packet. |
| 383 // The value contains two parts (A+B), where A is the delay of the | 406 // The value contains two parts (A+B), where A is the delay of the |
| 384 // first audio frame in the packet and B is the extra delay | 407 // first audio frame in the packet and B is the extra delay |
| 385 // contained in any stored data. Unit is in audio frames. | 408 // contained in any stored data. Unit is in audio frames. |
| 386 QueryPerformanceCounter(&now_count); | 409 QueryPerformanceCounter(&now_count); |
| 387 double audio_delay_frames = | 410 double audio_delay_frames = |
| 388 ((perf_count_to_100ns_units_ * now_count.QuadPart - | 411 ((perf_count_to_100ns_units_ * now_count.QuadPart - |
| 389 first_audio_frame_timestamp) / 10000.0) * ms_to_frame_count_ + | 412 first_audio_frame_timestamp) / 10000.0) * ms_to_frame_count_ + |
| 390 buffer_frame_index - num_frames_to_read; | 413 buffer_frame_index - num_frames_to_read; |
| 391 | 414 |
| 415 // Query a new volume level if AGC is enabled and if it is time to | |
| 416 // update the old value. | |
| 417 if (GetAutomaticGainControl()) { | |
|
tommi (sloooow) - chröme
2012/03/16 13:31:05
this code looks the same too
| |
| 418 base::Time now = base::Time::Now(); | |
| 419 if ((now - last_volume_update_time_).InMilliseconds() > | |
| 420 kMinIntervalBetweenVolumeUpdatesMs) { | |
| 421 // Retrieve the current volume level. Range is [0.0,1.0]. | |
| 422 float level = 0.0f; | |
| 423 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level); | |
| 424 if (SUCCEEDED(hr)) | |
| 425 volume_ = static_cast<double>(level); | |
| 426 last_volume_update_time_ = now; | |
| 427 } | |
| 428 } | |
| 429 | |
| 392 // Deliver captured data to the registered consumer using a packet | 430 // Deliver captured data to the registered consumer using a packet |
| 393 // size which was specified at construction. | 431 // size which was specified at construction. |
| 394 uint32 delay_frames = static_cast<uint32>(audio_delay_frames + 0.5); | 432 uint32 delay_frames = static_cast<uint32>(audio_delay_frames + 0.5); |
| 395 while (buffer_frame_index >= packet_size_frames_) { | 433 while (buffer_frame_index >= packet_size_frames_) { |
| 396 uint8* audio_data = | 434 uint8* audio_data = |
| 397 reinterpret_cast<uint8*>(capture_buffer.get()); | 435 reinterpret_cast<uint8*>(capture_buffer.get()); |
| 398 | 436 |
| 399 // Deliver data packet and delay estimation to the user. | 437 // Deliver data packet, delay estimation and volume level to |
| 438 // the user. | |
| 400 sink_->OnData(this, | 439 sink_->OnData(this, |
| 401 audio_data, | 440 audio_data, |
| 402 packet_size_bytes_, | 441 packet_size_bytes_, |
| 403 delay_frames * frame_size_); | 442 delay_frames * frame_size_, |
| 443 volume_); | |
| 404 | 444 |
| 405 // Store parts of the recorded data which can't be delivered | 445 // Store parts of the recorded data which can't be delivered |
| 406 // using the current packet size. The stored section will be used | 446 // using the current packet size. The stored section will be used |
| 407 // either in the next while-loop iteration or in the next | 447 // either in the next while-loop iteration or in the next |
| 408 // capture event. | 448 // capture event. |
| 409 memmove(&capture_buffer[0], | 449 memmove(&capture_buffer[0], |
| 410 &capture_buffer[packet_size_bytes_], | 450 &capture_buffer[packet_size_bytes_], |
| 411 (buffer_frame_index - packet_size_frames_) * frame_size_); | 451 (buffer_frame_index - packet_size_frames_) * frame_size_); |
| 412 | 452 |
| 413 buffer_frame_index -= packet_size_frames_; | 453 buffer_frame_index -= packet_size_frames_; |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 618 audio_capture_client_.ReceiveVoid()); | 658 audio_capture_client_.ReceiveVoid()); |
| 619 if (FAILED(hr)) | 659 if (FAILED(hr)) |
| 620 return hr; | 660 return hr; |
| 621 | 661 |
| 622 // Obtain a reference to the ISimpleAudioVolume interface which enables | 662 // Obtain a reference to the ISimpleAudioVolume interface which enables |
| 623 // us to control the master volume level of an audio session. | 663 // us to control the master volume level of an audio session. |
| 624 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), | 664 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), |
| 625 simple_audio_volume_.ReceiveVoid()); | 665 simple_audio_volume_.ReceiveVoid()); |
| 626 return hr; | 666 return hr; |
| 627 } | 667 } |
| OLD | NEW |