Chromium Code Reviews| Index: media/audio/mac/audio_low_latency_input_mac.cc |
| diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc |
| index 36858acaea72197ca17b0bc5d4412bd65578ec7d..8769fc2d44a8b0096c7009573cacfb7d198c4824 100644 |
| --- a/media/audio/mac/audio_low_latency_input_mac.cc |
| +++ b/media/audio/mac/audio_low_latency_input_mac.cc |
| @@ -37,7 +37,8 @@ AUAudioInputStream::AUAudioInputStream( |
| audio_unit_(0), |
| input_device_id_(audio_device_id), |
| started_(false), |
| - hardware_latency_frames_(0) { |
| + hardware_latency_frames_(0), |
| + number_of_channels_in_frame_(0) { |
| DCHECK(manager_); |
| // Set up the desired (output) format specified by the client. |
| @@ -211,6 +212,8 @@ bool AUAudioInputStream::Open() { |
| // The hardware latency is fixed and will not change during the call. |
| hardware_latency_frames_ = GetHardwareLatency(); |
| + number_of_channels_in_frame_ = GetNumberOfChannelsFromStream(); |
| + |
| return true; |
| } |
| @@ -263,6 +266,126 @@ void AUAudioInputStream::Close() { |
| manager_->ReleaseInputStream(this); |
| } |
| +double AUAudioInputStream::GetMaxVolume() { |
| + // Verify that we have a valid device. |
| + if (input_device_id_ == kAudioObjectUnknown) |
| + return 0.0; |
| + |
| + for (UInt32 i = 0; i <= number_of_channels_in_frame_; i++) { |
| + // If the volume is settable, the valid volume range is [0.0, 1.0]. |
|
henrika (OOO until Aug 14)
2012/02/23 11:50:41
How do you know that this is a true statement?
no longer working on chromium
2012/02/24 09:27:48
From Apple document:
kAudioDevicePropertyVolumeSca
|
| + if (IsVolumeSettableOnChannel(i)) |
| + return 1.0; |
| + } |
| + |
| + // Volume control is not available for the audio stream. |
| + return 0.0; |
| +} |
| + |
| +void AUAudioInputStream::SetVolume(double volume) { |
| + DCHECK(volume <= 1.0 && volume >= 0.0); |
| + |
| + // Verify that we have a valid device. |
| + if (input_device_id_ == kAudioObjectUnknown) |
| + return; |
| + |
| + Float32 volume_float32 = static_cast<Float32> (volume); |
| + AudioObjectPropertyAddress property_address = { |
| + kAudioDevicePropertyVolumeScalar, |
| + kAudioDevicePropertyScopeInput, |
| + kAudioObjectPropertyElementMaster |
| + }; |
| + |
| + // Try to set the volume for master volume channel. |
| + if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) { |
| + UInt32 size = sizeof(volume_float32); |
| + OSStatus result = AudioObjectSetPropertyData(input_device_id_, |
| + &property_address, |
| + 0, |
| + NULL, |
| + size, |
| + &volume_float32); |
| + DLOG_IF(WARNING, result != noErr) << "SetVolume failed to set volume to " |
| + << volume_float32; |
| + return; |
| + } |
| + |
| + // There is no master volume control, try to set volume for each channel. |
| + int success_on_channel = 0; |
| + for (UInt32 i = 1; i <= number_of_channels_in_frame_; i++) { |
| + property_address.mElement = i; |
| + if (IsVolumeSettableOnChannel(i)) { |
| + UInt32 size = sizeof(volume_float32); |
| + OSStatus result = AudioObjectSetPropertyData(input_device_id_, |
| + &property_address, |
| + 0, |
| + NULL, |
| + size, |
| + &volume_float32); |
| + if (result == noErr) |
| + ++success_on_channel; |
| + } |
| + } |
| + |
| + DLOG_IF(WARNING, success_on_channel == 0) |
| + << "SetVolume failed to set volume to " << volume_float32; |
| +} |
| + |
| +double AUAudioInputStream::GetVolume() { |
| + // Verify that we have a valid device. |
| + if (input_device_id_ == kAudioObjectUnknown) |
| + return 0.0; |
| + |
| + AudioObjectPropertyAddress property_address = { |
| + kAudioDevicePropertyVolumeScalar, |
| + kAudioDevicePropertyScopeInput, |
| + kAudioObjectPropertyElementMaster |
| + }; |
| + |
| + if (AudioObjectHasProperty(input_device_id_, &property_address)) { |
| + // The device supports master volume control, get the volume from the |
| + // master channel. |
| + Float32 volume_float32 = 0.0; |
| + UInt32 size = sizeof(volume_float32); |
| + OSStatus result = AudioObjectGetPropertyData(input_device_id_, |
| + &property_address, |
| + 0, |
| + NULL, |
| + &size, |
| + &volume_float32); |
| + if (result == noErr) |
| + return static_cast<double> (volume_float32); |
| + } else { |
| + // There is no master volume control, try to get the average volume of |
| + // all the channels. |
| + Float32 volume_float32 = 0.0; |
| + int success_on_channel = 0; |
| + for (UInt32 i = 1; i <= number_of_channels_in_frame_; i++) { |
| + property_address.mElement = i; |
| + if (AudioObjectHasProperty(input_device_id_, &property_address)) { |
| + Float32 channel_volume = 0; |
| + UInt32 size = sizeof(channel_volume); |
| + OSStatus result = AudioObjectGetPropertyData(input_device_id_, |
| + &property_address, |
| + 0, |
| + NULL, |
| + &size, |
| + &channel_volume); |
| + if (result == noErr) { |
| + volume_float32 += channel_volume; |
| + ++success_on_channel; |
| + } |
| + } |
| + } |
| + |
| + // Get the average volume of the channels. |
| + if (success_on_channel != 0) |
| + return static_cast<double> (volume_float32 / success_on_channel); |
| + } |
| + |
| + DLOG(WARNING) << "AudioObjectGetPropertyData failed not get volume"; |
|
henrika (OOO until Aug 14)
2012/02/23 11:50:41
Clean up the comment. "failed not get volume" ...
no longer working on chromium
2012/02/24 09:27:48
Done.
|
| + return 0.0; |
| +} |
| + |
| // AUHAL AudioDeviceOutput unit callback |
| OSStatus AUAudioInputStream::InputProc(void* user_data, |
| AudioUnitRenderActionFlags* flags, |
| @@ -388,8 +511,39 @@ double AUAudioInputStream::GetHardwareLatency() { |
| &device_latency_frames); |
| DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; |
| + // Get the stream latency. |
|
henrika (OOO until Aug 14)
2012/02/23 11:50:41
I don't understand where this part comes from. Not
no longer working on chromium
2012/02/24 09:27:48
Sorry, merge error.
|
| + property_address.mSelector = kAudioDevicePropertyStreams; |
| + UInt32 stream_latency_frames = 0; |
| + size = 0; |
| + result = AudioObjectGetPropertyDataSize(input_device_id_, |
| + &property_address, |
| + 0, |
| + NULL, |
| + &size); |
| + if (!result) { |
| + scoped_ptr_malloc<AudioStreamID> |
| + streams(reinterpret_cast<AudioStreamID*>(malloc(size))); |
| + AudioStreamID* stream_ids = streams.get(); |
| + result = AudioObjectGetPropertyData(input_device_id_, |
| + &property_address, |
| + 0, |
| + NULL, |
| + &size, |
| + stream_ids); |
| + if (!result) { |
| + property_address.mSelector = kAudioStreamPropertyLatency; |
| + result = AudioObjectGetPropertyData(stream_ids[0], |
| + &property_address, |
| + 0, |
| + NULL, |
| + &size, |
| + &stream_latency_frames); |
| + } |
| + } |
| + DLOG_IF(WARNING, result != noErr) << "Could not get audio stream latency."; |
| + |
| return static_cast<double>((audio_unit_latency_sec * |
| - format_.mSampleRate) + device_latency_frames); |
| + format_.mSampleRate) + device_latency_frames + stream_latency_frames); |
| } |
| double AUAudioInputStream::GetCaptureLatency( |
| @@ -407,9 +561,43 @@ double AUAudioInputStream::GetCaptureLatency( |
| return (delay_frames + hardware_latency_frames_); |
| } |
| +UInt32 AUAudioInputStream::GetNumberOfChannelsFromStream() { |
| + // Get the stream format, to be able to read the number of channels. |
| + AudioObjectPropertyAddress property_address = { |
| + kAudioDevicePropertyStreamFormat, |
| + kAudioDevicePropertyScopeInput, |
| + kAudioObjectPropertyElementMaster |
| + }; |
| + AudioStreamBasicDescription stream_format; |
| + UInt32 size = sizeof(stream_format); |
| + OSStatus result = AudioObjectGetPropertyData(input_device_id_, |
| + &property_address, |
| + 0, |
| + NULL, |
| + &size, |
| + &stream_format); |
| + DLOG_IF(WARNING, result != noErr) << "Could not get stream format."; |
| + |
| + return stream_format.mChannelsPerFrame; |
| +} |
| + |
| void AUAudioInputStream::HandleError(OSStatus err) { |
| NOTREACHED() << "error " << GetMacOSStatusErrorString(err) |
| << " (" << err << ")"; |
| if (sink_) |
| sink_->OnError(this, static_cast<int>(err)); |
| } |
| + |
| +bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) { |
| + Boolean is_settable = false; |
| + AudioObjectPropertyAddress property_address = { |
| + kAudioDevicePropertyVolumeScalar, |
| + kAudioDevicePropertyScopeInput, |
| + kAudioObjectPropertyElementMaster |
| + }; |
| + property_address.mElement = channel; |
| + OSStatus result = AudioObjectIsPropertySettable(input_device_id_, |
| + &property_address, |
| + &is_settable); |
| + return (result == noErr) ? is_settable : false; |
| +} |