Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Side by Side Diff: media/audio/win/audio_low_latency_input_win.cc

Issue 155863003: Add basic support for "googDucking" to getUserMedia on Windows. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/strings/utf_string_conversions.h" 9 #include "base/strings/utf_string_conversions.h"
10 #include "media/audio/win/audio_manager_win.h" 10 #include "media/audio/win/audio_manager_win.h"
11 #include "media/audio/win/avrt_wrapper_win.h" 11 #include "media/audio/win/avrt_wrapper_win.h"
12 12
13 using base::win::ScopedComPtr; 13 using base::win::ScopedComPtr;
14 using base::win::ScopedCOMInitializer; 14 using base::win::ScopedCOMInitializer;
15 15
16 namespace media { 16 namespace media {
17 17
18 WASAPIAudioInputStream::WASAPIAudioInputStream( 18 WASAPIAudioInputStream::WASAPIAudioInputStream(
19 AudioManagerWin* manager, const AudioParameters& params, 19 AudioManagerWin* manager,
20 const AudioParameters& params,
20 const std::string& device_id) 21 const std::string& device_id)
21 : manager_(manager), 22 : manager_(manager),
22 capture_thread_(NULL), 23 capture_thread_(NULL),
23 opened_(false), 24 opened_(false),
24 started_(false), 25 started_(false),
26 frame_size_(0),
27 packet_size_frames_(0),
28 packet_size_bytes_(0),
25 endpoint_buffer_size_frames_(0), 29 endpoint_buffer_size_frames_(0),
30 effects_(params.effects()),
26 device_id_(device_id), 31 device_id_(device_id),
32 perf_count_to_100ns_units_(0.0),
33 ms_to_frame_count_(0.0),
27 sink_(NULL) { 34 sink_(NULL) {
28 DCHECK(manager_); 35 DCHECK(manager_);
29 36
30 // Load the Avrt DLL if not already loaded. Required to support MMCSS. 37 // Load the Avrt DLL if not already loaded. Required to support MMCSS.
31 bool avrt_init = avrt::Initialize(); 38 bool avrt_init = avrt::Initialize();
32 DCHECK(avrt_init) << "Failed to load the Avrt.dll"; 39 DCHECK(avrt_init) << "Failed to load the Avrt.dll";
33 40
34 // Set up the desired capture format specified by the client. 41 // Set up the desired capture format specified by the client.
35 format_.nSamplesPerSec = params.sample_rate(); 42 format_.nSamplesPerSec = params.sample_rate();
36 format_.wFormatTag = WAVE_FORMAT_PCM; 43 format_.wFormatTag = WAVE_FORMAT_PCM;
(...skipping 23 matching lines...) Expand all
60 stop_capture_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); 67 stop_capture_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
61 DCHECK(stop_capture_event_.IsValid()); 68 DCHECK(stop_capture_event_.IsValid());
62 69
63 ms_to_frame_count_ = static_cast<double>(params.sample_rate()) / 1000.0; 70 ms_to_frame_count_ = static_cast<double>(params.sample_rate()) / 1000.0;
64 71
65 LARGE_INTEGER performance_frequency; 72 LARGE_INTEGER performance_frequency;
66 if (QueryPerformanceFrequency(&performance_frequency)) { 73 if (QueryPerformanceFrequency(&performance_frequency)) {
67 perf_count_to_100ns_units_ = 74 perf_count_to_100ns_units_ =
68 (10000000.0 / static_cast<double>(performance_frequency.QuadPart)); 75 (10000000.0 / static_cast<double>(performance_frequency.QuadPart));
69 } else { 76 } else {
70 LOG(ERROR) << "High-resolution performance counters are not supported."; 77 DLOG(ERROR) << "High-resolution performance counters are not supported.";
71 perf_count_to_100ns_units_ = 0.0;
72 } 78 }
73 } 79 }
74 80
75 WASAPIAudioInputStream::~WASAPIAudioInputStream() {} 81 WASAPIAudioInputStream::~WASAPIAudioInputStream() {}
76 82
77 bool WASAPIAudioInputStream::Open() { 83 bool WASAPIAudioInputStream::Open() {
78 DCHECK(CalledOnValidThread()); 84 DCHECK(CalledOnValidThread());
79 // Verify that we are not already opened. 85 // Verify that we are not already opened.
80 if (opened_) 86 if (opened_)
81 return false; 87 return false;
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 237
232 // Retrieve the current volume level. The value is in the range 0.0 to 1.0. 238 // Retrieve the current volume level. The value is in the range 0.0 to 1.0.
233 float level = 0.0f; 239 float level = 0.0f;
234 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level); 240 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level);
235 DLOG_IF(WARNING, FAILED(hr)) << "Failed to get input master volume."; 241 DLOG_IF(WARNING, FAILED(hr)) << "Failed to get input master volume.";
236 242
237 return static_cast<double>(level); 243 return static_cast<double>(level);
238 } 244 }
239 245
240 // static 246 // static
241 int WASAPIAudioInputStream::HardwareSampleRate( 247 AudioParameters WASAPIAudioInputStream::GetInputStreamParameters(
242 const std::string& device_id) { 248 const std::string& device_id) {
249 int sample_rate = 48000;
250 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
251
243 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format; 252 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format;
244 HRESULT hr = GetMixFormat(device_id, &audio_engine_mix_format); 253 if (SUCCEEDED(GetMixFormat(device_id, &audio_engine_mix_format))) {
245 if (FAILED(hr)) 254 sample_rate = static_cast<int>(audio_engine_mix_format->nSamplesPerSec);
246 return 0; 255 channel_layout = audio_engine_mix_format->nChannels == 1 ?
DaleCurtis 2014/02/05 22:15:43 Won't this blow up on multichannel input systems?
tommi (sloooow) - chröme 2014/02/06 11:50:34 Henrik - I guess this is rather a question for you
henrika (OOO until Aug 14) 2014/02/06 12:07:56 Well, as Tommi states, nothing is changed here. I
tommi (sloooow) - chröme 2014/02/06 12:55:34 Multichannel devices that I've tried, all support
henrika (OOO until Aug 14) 2014/02/06 13:11:28 Hope I am not repeating anything here but we are t
tommi (sloooow) - chröme 2014/02/06 13:28:33 Ah, sorry, brainfart :) Yes we are. I haven't te
256 CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO;
257 }
247 258
248 return static_cast<int>(audio_engine_mix_format->nSamplesPerSec); 259 int effects = AudioParameters::NO_EFFECTS;
260 // For non-loopback devices, advertise that ducking is supported.
261 if (device_id != AudioManagerBase::kLoopbackInputDeviceId)
262 effects |= AudioParameters::DUCKING;
263
264 // Use 10ms frame size as default.
265 int frames_per_buffer = sample_rate / 100;
henrika (OOO until Aug 14) 2014/02/05 16:19:01 Have you been able to verify this change somehow?
no longer working on chromium 2014/02/05 16:43:25 I did a quick check on the code, speech is using t
tommi (sloooow) - chröme 2014/02/06 11:50:34 In practice it's actually not a big change for two
266 return AudioParameters(
267 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0, sample_rate,
268 16, frames_per_buffer, effects);
249 } 269 }
250 270
251 // static 271 // static
252 uint32 WASAPIAudioInputStream::HardwareChannelCount(
253 const std::string& device_id) {
254 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format;
255 HRESULT hr = GetMixFormat(device_id, &audio_engine_mix_format);
256 if (FAILED(hr))
257 return 0;
258
259 return static_cast<uint32>(audio_engine_mix_format->nChannels);
260 }
261
262 // static
263 HRESULT WASAPIAudioInputStream::GetMixFormat(const std::string& device_id, 272 HRESULT WASAPIAudioInputStream::GetMixFormat(const std::string& device_id,
264 WAVEFORMATEX** device_format) { 273 WAVEFORMATEX** device_format) {
265 // It is assumed that this static method is called from a COM thread, i.e., 274 // It is assumed that this static method is called from a COM thread, i.e.,
266 // CoInitializeEx() is not called here to avoid STA/MTA conflicts. 275 // CoInitializeEx() is not called here to avoid STA/MTA conflicts.
267 ScopedComPtr<IMMDeviceEnumerator> enumerator; 276 ScopedComPtr<IMMDeviceEnumerator> enumerator;
268 HRESULT hr = enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), NULL, 277 HRESULT hr = enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), NULL,
269 CLSCTX_INPROC_SERVER); 278 CLSCTX_INPROC_SERVER);
270 if (FAILED(hr)) 279 if (FAILED(hr))
271 return hr; 280 return hr;
272 281
273 ScopedComPtr<IMMDevice> endpoint_device; 282 ScopedComPtr<IMMDevice> endpoint_device;
274 if (device_id == AudioManagerBase::kDefaultDeviceId) { 283 if (device_id == AudioManagerBase::kDefaultDeviceId) {
275 // Retrieve the default capture audio endpoint. 284 // Retrieve the default capture audio endpoint.
276 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole, 285 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole,
277 endpoint_device.Receive()); 286 endpoint_device.Receive());
278 } else if (device_id == AudioManagerBase::kLoopbackInputDeviceId) { 287 } else if (device_id == AudioManagerBase::kLoopbackInputDeviceId) {
279 // Capture the default playback stream. 288 // Get the mix format of the default playback stream.
280 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, 289 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
281 endpoint_device.Receive()); 290 endpoint_device.Receive());
282 } else { 291 } else {
283 // Retrieve a capture endpoint device that is specified by an endpoint 292 // Retrieve a capture endpoint device that is specified by an endpoint
284 // device-identification string. 293 // device-identification string.
285 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id).c_str(), 294 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id).c_str(),
286 endpoint_device.Receive()); 295 endpoint_device.Receive());
287 } 296 }
288 if (FAILED(hr)) 297 if (FAILED(hr))
289 return hr; 298 return hr;
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
462 if (FAILED(hr)) 471 if (FAILED(hr))
463 return hr; 472 return hr;
464 473
465 // Retrieve the IMMDevice by using the specified role or the specified 474 // Retrieve the IMMDevice by using the specified role or the specified
466 // unique endpoint device-identification string. 475 // unique endpoint device-identification string.
467 // TODO(henrika): possibly add support for the eCommunications as well. 476 // TODO(henrika): possibly add support for the eCommunications as well.
468 if (device_id_ == AudioManagerBase::kDefaultDeviceId) { 477 if (device_id_ == AudioManagerBase::kDefaultDeviceId) {
469 // Retrieve the default capture audio endpoint for the specified role. 478 // Retrieve the default capture audio endpoint for the specified role.
470 // Note that, in Windows Vista, the MMDevice API supports device roles 479 // Note that, in Windows Vista, the MMDevice API supports device roles
471 // but the system-supplied user interface programs do not. 480 // but the system-supplied user interface programs do not.
472 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole, 481
482 // If the caller has requested to turn on ducking, we select the default
483 // communications device instead of the default capture device.
484 // This implicitly turns on ducking and allows the user to control the
485 // attenuation level.
486 ERole role = (effects_ & AudioParameters::DUCKING) ?
487 eCommunications : eConsole;
488
489 hr = enumerator->GetDefaultAudioEndpoint(eCapture, role,
473 endpoint_device_.Receive()); 490 endpoint_device_.Receive());
474 } else if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) { 491 } else if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) {
475 // Capture the default playback stream. 492 // Capture the default playback stream.
476 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, 493 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
477 endpoint_device_.Receive()); 494 endpoint_device_.Receive());
478 } else { 495 } else {
479 // Retrieve a capture endpoint device that is specified by an endpoint 496 // Retrieve a capture endpoint device that is specified by an endpoint
480 // device-identification string. 497 // device-identification string.
498 // TODO(tommi): Opt into ducking for non-default audio devices.
499 DLOG_IF(WARNING, effects_ & AudioParameters::DUCKING)
500 << "Ducking has been requested for a non-default device."
501 "Not implemented.";
481 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id_).c_str(), 502 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id_).c_str(),
482 endpoint_device_.Receive()); 503 endpoint_device_.Receive());
483 } 504 }
484 505
485 if (FAILED(hr)) 506 if (FAILED(hr))
486 return hr; 507 return hr;
487 508
488 // Verify that the audio endpoint device is active, i.e., the audio 509 // Verify that the audio endpoint device is active, i.e., the audio
489 // adapter that connects to the endpoint device is present and enabled. 510 // adapter that connects to the endpoint device is present and enabled.
490 DWORD state = DEVICE_STATE_DISABLED; 511 DWORD state = DEVICE_STATE_DISABLED;
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
679 return hr; 700 return hr;
680 701
681 // Obtain a reference to the ISimpleAudioVolume interface which enables 702 // Obtain a reference to the ISimpleAudioVolume interface which enables
682 // us to control the master volume level of an audio session. 703 // us to control the master volume level of an audio session.
683 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), 704 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume),
684 simple_audio_volume_.ReceiveVoid()); 705 simple_audio_volume_.ReceiveVoid());
685 return hr; 706 return hr;
686 } 707 }
687 708
688 } // namespace media 709 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698