| 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..22b6df5ce169f78a70de6cbec04ae1071e30c54d 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.
|
| @@ -84,8 +85,10 @@ bool AUAudioInputStream::Open() {
|
| return false;
|
|
|
| // Verify that we have a valid device.
|
| - if (input_device_id_ == kAudioObjectUnknown)
|
| + if (input_device_id_ == kAudioObjectUnknown) {
|
| + NOTREACHED() << "Device ID is unknown";
|
| return false;
|
| + }
|
|
|
| // Start by obtaining an AudioOuputUnit using an AUHAL component description.
|
|
|
| @@ -211,6 +214,10 @@ bool AUAudioInputStream::Open() {
|
| // The hardware latency is fixed and will not change during the call.
|
| hardware_latency_frames_ = GetHardwareLatency();
|
|
|
| + // The master channel is 0, Left and right are channels 1 and 2.
|
| + // And the master channel is not counted in |number_of_channels_in_frame_|.
|
| + number_of_channels_in_frame_ = GetNumberOfChannelsFromStream();
|
| +
|
| return true;
|
| }
|
|
|
| @@ -263,6 +270,132 @@ void AUAudioInputStream::Close() {
|
| manager_->ReleaseInputStream(this);
|
| }
|
|
|
| +double AUAudioInputStream::GetMaxVolume() {
|
| + // Verify that we have a valid device.
|
| + if (input_device_id_ == kAudioObjectUnknown) {
|
| + NOTREACHED() << "Device ID is unknown";
|
| + return 0.0;
|
| + }
|
| +
|
| + // Query if any of the master, left or right channels has volume control.
|
| + for (int i = 0; i <= number_of_channels_in_frame_; ++i) {
|
| + // If the volume is settable, the valid volume range is [0.0, 1.0].
|
| + 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) {
|
| + NOTREACHED() << "Device ID is unknown";
|
| + 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)) {
|
| + OSStatus result = AudioObjectSetPropertyData(input_device_id_,
|
| + &property_address,
|
| + 0,
|
| + NULL,
|
| + sizeof(volume_float32),
|
| + &volume_float32);
|
| + if (result != noErr) {
|
| + DLOG(WARNING) << "Failed to set volume to " << volume_float32;
|
| + }
|
| + return;
|
| + }
|
| +
|
| + // There is no master volume control, try to set volume for each channel.
|
| + int successful_channels = 0;
|
| + for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
|
| + property_address.mElement = static_cast<UInt32>(i);
|
| + if (IsVolumeSettableOnChannel(i)) {
|
| + OSStatus result = AudioObjectSetPropertyData(input_device_id_,
|
| + &property_address,
|
| + 0,
|
| + NULL,
|
| + sizeof(volume_float32),
|
| + &volume_float32);
|
| + if (result == noErr)
|
| + ++successful_channels;
|
| + }
|
| + }
|
| +
|
| + DLOG_IF(WARNING, successful_channels == 0)
|
| + << "Failed to set volume to " << volume_float32;
|
| +}
|
| +
|
| +double AUAudioInputStream::GetVolume() {
|
| + // Verify that we have a valid device.
|
| + if (input_device_id_ == kAudioObjectUnknown){
|
| + NOTREACHED() << "Device ID is unknown";
|
| + 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 successful_channels = 0;
|
| + for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
|
| + property_address.mElement = static_cast<UInt32>(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;
|
| + ++successful_channels;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Get the average volume of the channels.
|
| + if (successful_channels != 0)
|
| + return static_cast<double>(volume_float32 / successful_channels);
|
| + }
|
| +
|
| + DLOG(WARNING) << "Failed to get volume";
|
| + return 0.0;
|
| +}
|
| +
|
| // AUHAL AudioDeviceOutput unit callback
|
| OSStatus AUAudioInputStream::InputProc(void* user_data,
|
| AudioUnitRenderActionFlags* flags,
|
| @@ -407,9 +540,45 @@ double AUAudioInputStream::GetCaptureLatency(
|
| return (delay_frames + hardware_latency_frames_);
|
| }
|
|
|
| +int 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);
|
| + if (result != noErr) {
|
| + DLOG(WARNING) << "Could not get stream format";
|
| + return 0;
|
| + }
|
| +
|
| + return static_cast<int>(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,
|
| + static_cast<UInt32>(channel)
|
| + };
|
| + OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
|
| + &property_address,
|
| + &is_settable);
|
| + return (result == noErr) ? is_settable : false;
|
| +}
|
|
|