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/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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |