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

Side by Side Diff: media/audio/mac/audio_low_latency_input_mac.cc

Issue 9702019: Adds Analog Gain Control (AGC) to the WebRTC client. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improved volume updating on Mac Created 8 years, 9 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 | Annotate | Revision Log
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/mac/audio_low_latency_input_mac.h" 5 #include "media/audio/mac/audio_low_latency_input_mac.h"
6 6
7 #include <CoreServices/CoreServices.h> 7 #include <CoreServices/CoreServices.h>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/mac/mac_logging.h" 11 #include "base/mac/mac_logging.h"
12 #include "media/audio/audio_util.h" 12 #include "media/audio/audio_util.h"
13 #include "media/audio/mac/audio_manager_mac.h" 13 #include "media/audio/mac/audio_manager_mac.h"
14 14
15 static const int kMinIntervalBetweenVolumeUpdatesMs = 1000;
16
15 static std::ostream& operator<<(std::ostream& os, 17 static std::ostream& operator<<(std::ostream& os,
16 const AudioStreamBasicDescription& format) { 18 const AudioStreamBasicDescription& format) {
17 os << "sample rate : " << format.mSampleRate << std::endl 19 os << "sample rate : " << format.mSampleRate << std::endl
18 << "format ID : " << format.mFormatID << std::endl 20 << "format ID : " << format.mFormatID << std::endl
19 << "format flags : " << format.mFormatFlags << std::endl 21 << "format flags : " << format.mFormatFlags << std::endl
20 << "bytes per packet : " << format.mBytesPerPacket << std::endl 22 << "bytes per packet : " << format.mBytesPerPacket << std::endl
21 << "frames per packet : " << format.mFramesPerPacket << std::endl 23 << "frames per packet : " << format.mFramesPerPacket << std::endl
22 << "bytes per frame : " << format.mBytesPerFrame << std::endl 24 << "bytes per frame : " << format.mBytesPerFrame << std::endl
23 << "channels per frame: " << format.mChannelsPerFrame << std::endl 25 << "channels per frame: " << format.mChannelsPerFrame << std::endl
24 << "bits per channel : " << format.mBitsPerChannel; 26 << "bits per channel : " << format.mBitsPerChannel;
25 return os; 27 return os;
26 } 28 }
27 29
28 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit" 30 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit"
29 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html 31 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html
30 // for more details and background regarding this implementation. 32 // for more details and background regarding this implementation.
31 33
32 AUAudioInputStream::AUAudioInputStream( 34 AUAudioInputStream::AUAudioInputStream(
33 AudioManagerMac* manager, const AudioParameters& params, 35 AudioManagerMac* manager, const AudioParameters& params,
34 AudioDeviceID audio_device_id) 36 AudioDeviceID audio_device_id)
35 : manager_(manager), 37 : manager_(manager),
36 sink_(NULL), 38 sink_(NULL),
37 audio_unit_(0), 39 audio_unit_(0),
38 input_device_id_(audio_device_id), 40 input_device_id_(audio_device_id),
39 started_(false), 41 started_(false),
40 hardware_latency_frames_(0), 42 hardware_latency_frames_(0),
41 number_of_channels_in_frame_(0) { 43 number_of_channels_in_frame_(0),
44 volume_(0.0),
45 agc_is_enabled_(0) {
42 DCHECK(manager_); 46 DCHECK(manager_);
43 47
44 // Set up the desired (output) format specified by the client. 48 // Set up the desired (output) format specified by the client.
45 format_.mSampleRate = params.sample_rate; 49 format_.mSampleRate = params.sample_rate;
46 format_.mFormatID = kAudioFormatLinearPCM; 50 format_.mFormatID = kAudioFormatLinearPCM;
47 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | 51 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
48 kLinearPCMFormatFlagIsSignedInteger; 52 kLinearPCMFormatFlagIsSignedInteger;
49 format_.mBitsPerChannel = params.bits_per_sample; 53 format_.mBitsPerChannel = params.bits_per_sample;
50 format_.mChannelsPerFrame = params.channels; 54 format_.mChannelsPerFrame = params.channels;
51 format_.mFramesPerPacket = 1; // uncompressed audio 55 format_.mFramesPerPacket = 1; // uncompressed audio
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 if (IsVolumeSettableOnChannel(i)) 287 if (IsVolumeSettableOnChannel(i))
284 return 1.0; 288 return 1.0;
285 } 289 }
286 290
287 // Volume control is not available for the audio stream. 291 // Volume control is not available for the audio stream.
288 return 0.0; 292 return 0.0;
289 } 293 }
290 294
291 void AUAudioInputStream::SetVolume(double volume) { 295 void AUAudioInputStream::SetVolume(double volume) {
292 DCHECK(volume <= 1.0 && volume >= 0.0); 296 DCHECK(volume <= 1.0 && volume >= 0.0);
297 // TODO(henrika): remove!
298 DLOG(INFO) << "SetVolume(volume=" << volume << ")";
tommi (sloooow) - chröme 2012/03/16 13:31:05 ping
henrika (OOO until Aug 14) 2012/03/21 10:16:04 Done.
293 299
294 // Verify that we have a valid device. 300 // Verify that we have a valid device.
295 if (input_device_id_ == kAudioObjectUnknown) { 301 if (input_device_id_ == kAudioObjectUnknown) {
296 NOTREACHED() << "Device ID is unknown"; 302 NOTREACHED() << "Device ID is unknown";
297 return; 303 return;
298 } 304 }
299 305
300 Float32 volume_float32 = static_cast<Float32>(volume); 306 Float32 volume_float32 = static_cast<Float32>(volume);
301 AudioObjectPropertyAddress property_address = { 307 AudioObjectPropertyAddress property_address = {
302 kAudioDevicePropertyVolumeScalar, 308 kAudioDevicePropertyVolumeScalar,
(...skipping 26 matching lines...) Expand all
329 NULL, 335 NULL,
330 sizeof(volume_float32), 336 sizeof(volume_float32),
331 &volume_float32); 337 &volume_float32);
332 if (result == noErr) 338 if (result == noErr)
333 ++successful_channels; 339 ++successful_channels;
334 } 340 }
335 } 341 }
336 342
337 DLOG_IF(WARNING, successful_channels == 0) 343 DLOG_IF(WARNING, successful_channels == 0)
338 << "Failed to set volume to " << volume_float32; 344 << "Failed to set volume to " << volume_float32;
345
346 // We take new volume samples once every second when the AGC is enabled.
347 // To ensure that a new setting has an immediate effect, the new volume
348 // setting is cached here. It will ensure that the next OnData() callback
349 // will contain a new valid volume level. If this approach was not taken,
350 // we could report invalid volume levels to the client for a time period
351 // of up to one second.
352 if (GetAutomaticGainControl()) {
353 volume_ = GetVolume();
354 }
339 } 355 }
340 356
341 double AUAudioInputStream::GetVolume() { 357 double AUAudioInputStream::GetVolume() {
342 // Verify that we have a valid device. 358 // Verify that we have a valid device.
343 if (input_device_id_ == kAudioObjectUnknown){ 359 if (input_device_id_ == kAudioObjectUnknown){
344 NOTREACHED() << "Device ID is unknown"; 360 NOTREACHED() << "Device ID is unknown";
345 return 0.0; 361 return 0.0;
346 } 362 }
347 363
348 AudioObjectPropertyAddress property_address = { 364 AudioObjectPropertyAddress property_address = {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 405
390 // Get the average volume of the channels. 406 // Get the average volume of the channels.
391 if (successful_channels != 0) 407 if (successful_channels != 0)
392 return static_cast<double>(volume_float32 / successful_channels); 408 return static_cast<double>(volume_float32 / successful_channels);
393 } 409 }
394 410
395 DLOG(WARNING) << "Failed to get volume"; 411 DLOG(WARNING) << "Failed to get volume";
396 return 0.0; 412 return 0.0;
397 } 413 }
398 414
415 void AUAudioInputStream::SetAutomaticGainControl(bool enabled) {
416 base::subtle::Release_Store(&agc_is_enabled_, enabled);
417 }
418
419 bool AUAudioInputStream::GetAutomaticGainControl() {
420 return (base::subtle::Acquire_Load(&agc_is_enabled_) == 1);
421 }
422
399 // AUHAL AudioDeviceOutput unit callback 423 // AUHAL AudioDeviceOutput unit callback
400 OSStatus AUAudioInputStream::InputProc(void* user_data, 424 OSStatus AUAudioInputStream::InputProc(void* user_data,
401 AudioUnitRenderActionFlags* flags, 425 AudioUnitRenderActionFlags* flags,
402 const AudioTimeStamp* time_stamp, 426 const AudioTimeStamp* time_stamp,
403 UInt32 bus_number, 427 UInt32 bus_number,
404 UInt32 number_of_frames, 428 UInt32 number_of_frames,
405 AudioBufferList* io_data) { 429 AudioBufferList* io_data) {
406 // Verify that the correct bus is used (Input bus/Element 1) 430 // Verify that the correct bus is used (Input bus/Element 1)
407 DCHECK_EQ(bus_number, static_cast<UInt32>(1)); 431 DCHECK_EQ(bus_number, static_cast<UInt32>(1));
408 AUAudioInputStream* audio_input = 432 AUAudioInputStream* audio_input =
(...skipping 25 matching lines...) Expand all
434 double capture_latency_frames = GetCaptureLatency(time_stamp); 458 double capture_latency_frames = GetCaptureLatency(time_stamp);
435 459
436 AudioBuffer& buffer = io_data->mBuffers[0]; 460 AudioBuffer& buffer = io_data->mBuffers[0];
437 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); 461 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData);
438 uint32 capture_delay_bytes = static_cast<uint32> 462 uint32 capture_delay_bytes = static_cast<uint32>
439 ((capture_latency_frames + 0.5) * format_.mBytesPerFrame); 463 ((capture_latency_frames + 0.5) * format_.mBytesPerFrame);
440 DCHECK(audio_data); 464 DCHECK(audio_data);
441 if (!audio_data) 465 if (!audio_data)
442 return kAudioUnitErr_InvalidElement; 466 return kAudioUnitErr_InvalidElement;
443 467
444 sink_->OnData(this, audio_data, buffer.mDataByteSize, capture_delay_bytes); 468 // Query a new volume level if AGC is enabled and if it is time to update
469 // the old value.
470 if (GetAutomaticGainControl()) {
471 base::Time now = base::Time::Now();
472 if ((now - last_volume_update_time_).InMilliseconds() >
473 kMinIntervalBetweenVolumeUpdatesMs) {
474 // Retrieve the current volume level. Range is [0.0,1.0].
475 volume_ = static_cast<double>(GetVolume());
476 DLOG(INFO) << "Volume updated to: " << volume_;
scherkus (not reviewing) 2012/03/20 13:49:41 logspam
henrika (OOO until Aug 14) 2012/03/21 10:16:04 Done.
477 last_volume_update_time_ = now;
478 }
479 }
480
481 // Deliver data packet, delay estimation and volume level to the user.
482 sink_->OnData(this,
483 audio_data,
484 buffer.mDataByteSize,
485 capture_delay_bytes,
486 volume_);
445 487
446 return noErr; 488 return noErr;
447 } 489 }
448 490
449 double AUAudioInputStream::HardwareSampleRate() { 491 double AUAudioInputStream::HardwareSampleRate() {
450 // Determine the default input device's sample-rate. 492 // Determine the default input device's sample-rate.
451 AudioDeviceID device_id = kAudioObjectUnknown; 493 AudioDeviceID device_id = kAudioObjectUnknown;
452 UInt32 info_size = sizeof(device_id); 494 UInt32 info_size = sizeof(device_id);
453 495
454 AudioObjectPropertyAddress default_input_device_address = { 496 AudioObjectPropertyAddress default_input_device_address = {
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
575 AudioObjectPropertyAddress property_address = { 617 AudioObjectPropertyAddress property_address = {
576 kAudioDevicePropertyVolumeScalar, 618 kAudioDevicePropertyVolumeScalar,
577 kAudioDevicePropertyScopeInput, 619 kAudioDevicePropertyScopeInput,
578 static_cast<UInt32>(channel) 620 static_cast<UInt32>(channel)
579 }; 621 };
580 OSStatus result = AudioObjectIsPropertySettable(input_device_id_, 622 OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
581 &property_address, 623 &property_address,
582 &is_settable); 624 &is_settable);
583 return (result == noErr) ? is_settable : false; 625 return (result == noErr) ? is_settable : false;
584 } 626 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698