diff options
Diffstat (limited to 'webrtc/modules/audio_device/mac/audio_mixer_manager_mac.cc')
-rw-r--r-- | webrtc/modules/audio_device/mac/audio_mixer_manager_mac.cc | 1907 |
1 files changed, 881 insertions, 1026 deletions
diff --git a/webrtc/modules/audio_device/mac/audio_mixer_manager_mac.cc b/webrtc/modules/audio_device/mac/audio_mixer_manager_mac.cc index 9016ffe508..e7e0754695 100644 --- a/webrtc/modules/audio_device/mac/audio_mixer_manager_mac.cc +++ b/webrtc/modules/audio_device/mac/audio_mixer_manager_mac.cc @@ -11,1134 +11,989 @@ #include "webrtc/modules/audio_device/mac/audio_mixer_manager_mac.h" #include "webrtc/system_wrappers/include/trace.h" -#include <unistd.h> // getpid() +#include <unistd.h> // getpid() namespace webrtc { - -#define WEBRTC_CA_RETURN_ON_ERR(expr) \ - do { \ - err = expr; \ - if (err != noErr) { \ - logCAMsg(kTraceError, kTraceAudioDevice, _id, \ - "Error in " #expr, (const char *)&err); \ - return -1; \ - } \ - } while(0) - -#define WEBRTC_CA_LOG_ERR(expr) \ - do { \ - err = expr; \ - if (err != noErr) { \ - logCAMsg(kTraceError, kTraceAudioDevice, _id, \ - "Error in " #expr, (const char *)&err); \ - } \ - } while(0) - -#define WEBRTC_CA_LOG_WARN(expr) \ - do { \ - err = expr; \ - if (err != noErr) { \ - logCAMsg(kTraceWarning, kTraceAudioDevice, _id, \ - "Error in " #expr, (const char *)&err); \ - } \ - } while(0) - -AudioMixerManagerMac::AudioMixerManagerMac(const int32_t id) : - _critSect(*CriticalSectionWrapper::CreateCriticalSection()), - _id(id), - _inputDeviceID(kAudioObjectUnknown), - _outputDeviceID(kAudioObjectUnknown), - _noInputChannels(0), - _noOutputChannels(0) -{ - WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, - "%s constructed", __FUNCTION__); -} - -AudioMixerManagerMac::~AudioMixerManagerMac() -{ - WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, - "%s destructed", __FUNCTION__); - Close(); - - delete &_critSect; +#define WEBRTC_CA_RETURN_ON_ERR(expr) \ + do { \ + err = expr; \ + if (err != noErr) { \ + logCAMsg(kTraceError, kTraceAudioDevice, _id, "Error in " #expr, \ + (const char*) & err); \ + return -1; \ + } \ + } while (0) + +#define WEBRTC_CA_LOG_ERR(expr) \ + do { \ + err = expr; \ + if (err != noErr) { \ + logCAMsg(kTraceError, kTraceAudioDevice, _id, "Error in " #expr, \ + (const char*) & err); \ + } \ + } while (0) + +#define WEBRTC_CA_LOG_WARN(expr) \ + do { \ + err = expr; \ + if (err != noErr) { \ + logCAMsg(kTraceWarning, kTraceAudioDevice, _id, "Error in " #expr, \ + (const char*) & err); \ + } \ + } while (0) + +AudioMixerManagerMac::AudioMixerManagerMac(const int32_t id) + : _critSect(*CriticalSectionWrapper::CreateCriticalSection()), + _id(id), + _inputDeviceID(kAudioObjectUnknown), + _outputDeviceID(kAudioObjectUnknown), + _noInputChannels(0), + _noOutputChannels(0) { + WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s constructed", + __FUNCTION__); +} + +AudioMixerManagerMac::~AudioMixerManagerMac() { + WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destructed", + __FUNCTION__); + + Close(); + + delete &_critSect; } // ============================================================================ // PUBLIC METHODS // ============================================================================ -int32_t AudioMixerManagerMac::Close() -{ - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", - __FUNCTION__); +int32_t AudioMixerManagerMac::Close() { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); - CriticalSectionScoped lock(&_critSect); + CriticalSectionScoped lock(&_critSect); - CloseSpeaker(); - CloseMicrophone(); - - return 0; + CloseSpeaker(); + CloseMicrophone(); + return 0; } -int32_t AudioMixerManagerMac::CloseSpeaker() -{ - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", - __FUNCTION__); +int32_t AudioMixerManagerMac::CloseSpeaker() { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); - CriticalSectionScoped lock(&_critSect); + CriticalSectionScoped lock(&_critSect); - _outputDeviceID = kAudioObjectUnknown; - _noOutputChannels = 0; + _outputDeviceID = kAudioObjectUnknown; + _noOutputChannels = 0; - return 0; + return 0; } -int32_t AudioMixerManagerMac::CloseMicrophone() -{ - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", - __FUNCTION__); +int32_t AudioMixerManagerMac::CloseMicrophone() { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); - CriticalSectionScoped lock(&_critSect); + CriticalSectionScoped lock(&_critSect); - _inputDeviceID = kAudioObjectUnknown; - _noInputChannels = 0; + _inputDeviceID = kAudioObjectUnknown; + _noInputChannels = 0; - return 0; + return 0; } -int32_t AudioMixerManagerMac::OpenSpeaker(AudioDeviceID deviceID) -{ - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "AudioMixerManagerMac::OpenSpeaker(id=%d)", deviceID); - - CriticalSectionScoped lock(&_critSect); - - OSStatus err = noErr; - UInt32 size = 0; - pid_t hogPid = -1; +int32_t AudioMixerManagerMac::OpenSpeaker(AudioDeviceID deviceID) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "AudioMixerManagerMac::OpenSpeaker(id=%d)", deviceID); - _outputDeviceID = deviceID; + CriticalSectionScoped lock(&_critSect); - // Check which process, if any, has hogged the device. - AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyHogMode, - kAudioDevicePropertyScopeOutput, 0 }; + OSStatus err = noErr; + UInt32 size = 0; + pid_t hogPid = -1; - size = sizeof(hogPid); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, &size, &hogPid)); - - if (hogPid == -1) - { - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " No process has hogged the input device"); - } - // getpid() is apparently "always successful" - else if (hogPid == getpid()) - { - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " Our process has hogged the input device"); - } else - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Another process (pid = %d) has hogged the input device", - static_cast<int> (hogPid)); - - return -1; - } + _outputDeviceID = deviceID; - // get number of channels from stream format - propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; + // Check which process, if any, has hogged the device. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyHogMode, kAudioDevicePropertyScopeOutput, 0}; - // Get the stream format, to be able to read the number of channels. - AudioStreamBasicDescription streamFormat; - size = sizeof(AudioStreamBasicDescription); - memset(&streamFormat, 0, size); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, &size, &streamFormat)); + size = sizeof(hogPid); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &hogPid)); - _noOutputChannels = streamFormat.mChannelsPerFrame; - - return 0; -} - -int32_t AudioMixerManagerMac::OpenMicrophone(AudioDeviceID deviceID) -{ + if (hogPid == -1) { WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "AudioMixerManagerMac::OpenMicrophone(id=%d)", deviceID); - - CriticalSectionScoped lock(&_critSect); - - OSStatus err = noErr; - UInt32 size = 0; - pid_t hogPid = -1; - - _inputDeviceID = deviceID; - - // Check which process, if any, has hogged the device. - AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyHogMode, - kAudioDevicePropertyScopeInput, 0 }; - size = sizeof(hogPid); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &hogPid)); - if (hogPid == -1) - { - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " No process has hogged the input device"); - } - // getpid() is apparently "always successful" - else if (hogPid == getpid()) - { - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " Our process has hogged the input device"); - } else - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Another process (pid = %d) has hogged the input device", - static_cast<int> (hogPid)); - - return -1; - } - - // get number of channels from stream format - propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; - - // Get the stream format, to be able to read the number of channels. - AudioStreamBasicDescription streamFormat; - size = sizeof(AudioStreamBasicDescription); - memset(&streamFormat, 0, size); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &streamFormat)); - - _noInputChannels = streamFormat.mChannelsPerFrame; + " No process has hogged the input device"); + } + // getpid() is apparently "always successful" + else if (hogPid == getpid()) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " Our process has hogged the input device"); + } else { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Another process (pid = %d) has hogged the input device", + static_cast<int>(hogPid)); - return 0; -} + return -1; + } -bool AudioMixerManagerMac::SpeakerIsInitialized() const -{ - WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", - __FUNCTION__); + // get number of channels from stream format + propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; - return (_outputDeviceID != kAudioObjectUnknown); -} + // Get the stream format, to be able to read the number of channels. + AudioStreamBasicDescription streamFormat; + size = sizeof(AudioStreamBasicDescription); + memset(&streamFormat, 0, size); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &streamFormat)); -bool AudioMixerManagerMac::MicrophoneIsInitialized() const -{ - WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", - __FUNCTION__); + _noOutputChannels = streamFormat.mChannelsPerFrame; - return (_inputDeviceID != kAudioObjectUnknown); + return 0; } -int32_t AudioMixerManagerMac::SetSpeakerVolume(uint32_t volume) -{ - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "AudioMixerManagerMac::SetSpeakerVolume(volume=%u)", volume); +int32_t AudioMixerManagerMac::OpenMicrophone(AudioDeviceID deviceID) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "AudioMixerManagerMac::OpenMicrophone(id=%d)", deviceID); - CriticalSectionScoped lock(&_critSect); + CriticalSectionScoped lock(&_critSect); - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } + OSStatus err = noErr; + UInt32 size = 0; + pid_t hogPid = -1; - OSStatus err = noErr; - UInt32 size = 0; - bool success = false; + _inputDeviceID = deviceID; - // volume range is 0.0 - 1.0, convert from 0 -255 - const Float32 vol = (Float32)(volume / 255.0); + // Check which process, if any, has hogged the device. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyHogMode, kAudioDevicePropertyScopeInput, 0}; + size = sizeof(hogPid); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &hogPid)); + if (hogPid == -1) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " No process has hogged the input device"); + } + // getpid() is apparently "always successful" + else if (hogPid == getpid()) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " Our process has hogged the input device"); + } else { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Another process (pid = %d) has hogged the input device", + static_cast<int>(hogPid)); - assert(vol <= 1.0 && vol >= 0.0); + return -1; + } - // Does the capture device have a master volume control? - // If so, use it exclusively. - AudioObjectPropertyAddress propertyAddress = { - kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, - 0 }; - Boolean isSettable = false; - err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, - &isSettable); - if (err == noErr && isSettable) - { - size = sizeof(vol); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, size, &vol)); + // get number of channels from stream format + propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; - return 0; - } - - // Otherwise try to set each channel. - for (UInt32 i = 1; i <= _noOutputChannels; i++) - { - propertyAddress.mElement = i; - isSettable = false; - err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, - &isSettable); - if (err == noErr && isSettable) - { - size = sizeof(vol); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, size, &vol)); - } - success = true; - } + // Get the stream format, to be able to read the number of channels. + AudioStreamBasicDescription streamFormat; + size = sizeof(AudioStreamBasicDescription); + memset(&streamFormat, 0, size); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &streamFormat)); - if (!success) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Unable to set a volume on any output channel"); - return -1; - } + _noInputChannels = streamFormat.mChannelsPerFrame; - return 0; + return 0; } -int32_t AudioMixerManagerMac::SpeakerVolume(uint32_t& volume) const -{ +bool AudioMixerManagerMac::SpeakerIsInitialized() const { + WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - OSStatus err = noErr; - UInt32 size = 0; - unsigned int channels = 0; - Float32 channelVol = 0; - Float32 vol = 0; - - // Does the device have a master volume control? - // If so, use it exclusively. - AudioObjectPropertyAddress propertyAddress = { - kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, - 0 }; - Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID, - &propertyAddress); - if (hasProperty) - { - size = sizeof(vol); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, &size, &vol)); - - // vol 0.0 to 1.0 -> convert to 0 - 255 - volume = static_cast<uint32_t> (vol * 255 + 0.5); - } else - { - // Otherwise get the average volume across channels. - vol = 0; - for (UInt32 i = 1; i <= _noOutputChannels; i++) - { - channelVol = 0; - propertyAddress.mElement = i; - hasProperty = AudioObjectHasProperty(_outputDeviceID, - &propertyAddress); - if (hasProperty) - { - size = sizeof(channelVol); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, &size, &channelVol)); - - vol += channelVol; - channels++; - } - } - - if (channels == 0) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Unable to get a volume on any channel"); - return -1; - } - - assert(channels > 0); - // vol 0.0 to 1.0 -> convert to 0 - 255 - volume = static_cast<uint32_t> (255 * vol / channels + 0.5); - } - - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " AudioMixerManagerMac::SpeakerVolume() => vol=%i", vol); - - return 0; + return (_outputDeviceID != kAudioObjectUnknown); } -int32_t -AudioMixerManagerMac::MaxSpeakerVolume(uint32_t& maxVolume) const -{ +bool AudioMixerManagerMac::MicrophoneIsInitialized() const { + WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - // volume range is 0.0 to 1.0 - // we convert that to 0 - 255 - maxVolume = 255; - - return 0; + return (_inputDeviceID != kAudioObjectUnknown); } -int32_t -AudioMixerManagerMac::MinSpeakerVolume(uint32_t& minVolume) const -{ +int32_t AudioMixerManagerMac::SetSpeakerVolume(uint32_t volume) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "AudioMixerManagerMac::SetSpeakerVolume(volume=%u)", volume); - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } + CriticalSectionScoped lock(&_critSect); - // volume range is 0.0 to 1.0 - // we convert that to 0 - 255 - minVolume = 0; + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } - return 0; -} + OSStatus err = noErr; + UInt32 size = 0; + bool success = false; -int32_t -AudioMixerManagerMac::SpeakerVolumeStepSize(uint16_t& stepSize) const -{ + // volume range is 0.0 - 1.0, convert from 0 -255 + const Float32 vol = (Float32)(volume / 255.0); - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } + assert(vol <= 1.0 && vol >= 0.0); - // volume range is 0.0 to 1.0 - // we convert that to 0 - 255 - stepSize = 1; + // Does the capture device have a master volume control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, 0}; + Boolean isSettable = false; + err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, + &isSettable); + if (err == noErr && isSettable) { + size = sizeof(vol); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, size, &vol)); return 0; -} + } -int32_t AudioMixerManagerMac::SpeakerVolumeIsAvailable(bool& available) -{ - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - OSStatus err = noErr; - - // Does the capture device have a master volume control? - // If so, use it exclusively. - AudioObjectPropertyAddress propertyAddress = { - kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, - 0 }; - Boolean isSettable = false; + // Otherwise try to set each channel. + for (UInt32 i = 1; i <= _noOutputChannels; i++) { + propertyAddress.mElement = i; + isSettable = false; err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, &isSettable); - if (err == noErr && isSettable) - { - available = true; - return 0; - } - - // Otherwise try to set each channel. - for (UInt32 i = 1; i <= _noOutputChannels; i++) - { - propertyAddress.mElement = i; - isSettable = false; - err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, - &isSettable); - if (err != noErr || !isSettable) - { - available = false; - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Volume cannot be set for output channel %d, err=%d", - i, err); - return -1; - } - } - + if (err == noErr && isSettable) { + size = sizeof(vol); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, size, &vol)); + } + success = true; + } + + if (!success) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Unable to set a volume on any output channel"); + return -1; + } + + return 0; +} + +int32_t AudioMixerManagerMac::SpeakerVolume(uint32_t& volume) const { + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + UInt32 size = 0; + unsigned int channels = 0; + Float32 channelVol = 0; + Float32 vol = 0; + + // Does the device have a master volume control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, 0}; + Boolean hasProperty = + AudioObjectHasProperty(_outputDeviceID, &propertyAddress); + if (hasProperty) { + size = sizeof(vol); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &vol)); + + // vol 0.0 to 1.0 -> convert to 0 - 255 + volume = static_cast<uint32_t>(vol * 255 + 0.5); + } else { + // Otherwise get the average volume across channels. + vol = 0; + for (UInt32 i = 1; i <= _noOutputChannels; i++) { + channelVol = 0; + propertyAddress.mElement = i; + hasProperty = AudioObjectHasProperty(_outputDeviceID, &propertyAddress); + if (hasProperty) { + size = sizeof(channelVol); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &channelVol)); + + vol += channelVol; + channels++; + } + } + + if (channels == 0) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Unable to get a volume on any channel"); + return -1; + } + + assert(channels > 0); + // vol 0.0 to 1.0 -> convert to 0 - 255 + volume = static_cast<uint32_t>(255 * vol / channels + 0.5); + } + + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " AudioMixerManagerMac::SpeakerVolume() => vol=%i", vol); + + return 0; +} + +int32_t AudioMixerManagerMac::MaxSpeakerVolume(uint32_t& maxVolume) const { + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + // volume range is 0.0 to 1.0 + // we convert that to 0 - 255 + maxVolume = 255; + + return 0; +} + +int32_t AudioMixerManagerMac::MinSpeakerVolume(uint32_t& minVolume) const { + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + // volume range is 0.0 to 1.0 + // we convert that to 0 - 255 + minVolume = 0; + + return 0; +} + +int32_t AudioMixerManagerMac::SpeakerVolumeStepSize(uint16_t& stepSize) const { + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + // volume range is 0.0 to 1.0 + // we convert that to 0 - 255 + stepSize = 1; + + return 0; +} + +int32_t AudioMixerManagerMac::SpeakerVolumeIsAvailable(bool& available) { + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + + // Does the capture device have a master volume control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, 0}; + Boolean isSettable = false; + err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, + &isSettable); + if (err == noErr && isSettable) { available = true; return 0; -} - -int32_t AudioMixerManagerMac::SpeakerMuteIsAvailable(bool& available) -{ - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } + } - OSStatus err = noErr; - - // Does the capture device have a master mute control? - // If so, use it exclusively. - AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, - kAudioDevicePropertyScopeOutput, 0 }; - Boolean isSettable = false; + // Otherwise try to set each channel. + for (UInt32 i = 1; i <= _noOutputChannels; i++) { + propertyAddress.mElement = i; + isSettable = false; err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, &isSettable); - if (err == noErr && isSettable) - { - available = true; - return 0; - } - - // Otherwise try to set each channel. - for (UInt32 i = 1; i <= _noOutputChannels; i++) - { - propertyAddress.mElement = i; - isSettable = false; - err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, - &isSettable); - if (err != noErr || !isSettable) - { - available = false; - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Mute cannot be set for output channel %d, err=%d", - i, err); - return -1; - } - } - + if (err != noErr || !isSettable) { + available = false; + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Volume cannot be set for output channel %d, err=%d", i, + err); + return -1; + } + } + + available = true; + return 0; +} + +int32_t AudioMixerManagerMac::SpeakerMuteIsAvailable(bool& available) { + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + + // Does the capture device have a master mute control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, 0}; + Boolean isSettable = false; + err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, + &isSettable); + if (err == noErr && isSettable) { available = true; return 0; -} - -int32_t AudioMixerManagerMac::SetSpeakerMute(bool enable) -{ - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "AudioMixerManagerMac::SetSpeakerMute(enable=%u)", enable); - - CriticalSectionScoped lock(&_critSect); - - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - OSStatus err = noErr; - UInt32 size = 0; - UInt32 mute = enable ? 1 : 0; - bool success = false; + } - // Does the render device have a master mute control? - // If so, use it exclusively. - AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, - kAudioDevicePropertyScopeOutput, 0 }; - Boolean isSettable = false; + // Otherwise try to set each channel. + for (UInt32 i = 1; i <= _noOutputChannels; i++) { + propertyAddress.mElement = i; + isSettable = false; err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, &isSettable); - if (err == noErr && isSettable) - { - size = sizeof(mute); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, size, &mute)); - - return 0; - } - - // Otherwise try to set each channel. - for (UInt32 i = 1; i <= _noOutputChannels; i++) - { - propertyAddress.mElement = i; - isSettable = false; - err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, - &isSettable); - if (err == noErr && isSettable) - { - size = sizeof(mute); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, size, &mute)); - } - success = true; - } - - if (!success) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Unable to set mute on any input channel"); - return -1; - } + if (err != noErr || !isSettable) { + available = false; + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Mute cannot be set for output channel %d, err=%d", i, err); + return -1; + } + } + + available = true; + return 0; +} + +int32_t AudioMixerManagerMac::SetSpeakerMute(bool enable) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "AudioMixerManagerMac::SetSpeakerMute(enable=%u)", enable); + + CriticalSectionScoped lock(&_critSect); + + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + UInt32 size = 0; + UInt32 mute = enable ? 1 : 0; + bool success = false; + + // Does the render device have a master mute control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, 0}; + Boolean isSettable = false; + err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, + &isSettable); + if (err == noErr && isSettable) { + size = sizeof(mute); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, size, &mute)); return 0; -} + } -int32_t AudioMixerManagerMac::SpeakerMute(bool& enabled) const -{ - - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - OSStatus err = noErr; - UInt32 size = 0; - unsigned int channels = 0; - UInt32 channelMuted = 0; - UInt32 muted = 0; - - // Does the device have a master volume control? - // If so, use it exclusively. - AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, - kAudioDevicePropertyScopeOutput, 0 }; - Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID, - &propertyAddress); - if (hasProperty) - { - size = sizeof(muted); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, &size, &muted)); - - // 1 means muted - enabled = static_cast<bool> (muted); - } else - { - // Otherwise check if all channels are muted. - for (UInt32 i = 1; i <= _noOutputChannels; i++) - { - muted = 0; - propertyAddress.mElement = i; - hasProperty = AudioObjectHasProperty(_outputDeviceID, - &propertyAddress); - if (hasProperty) - { - size = sizeof(channelMuted); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, &size, &channelMuted)); - - muted = (muted && channelMuted); - channels++; - } - } - - if (channels == 0) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Unable to get mute for any channel"); - return -1; - } - - assert(channels > 0); - // 1 means muted - enabled = static_cast<bool> (muted); - } - - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " AudioMixerManagerMac::SpeakerMute() => enabled=%d, enabled"); - - return 0; -} - -int32_t AudioMixerManagerMac::StereoPlayoutIsAvailable(bool& available) -{ - if (_outputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - available = (_noOutputChannels == 2); - return 0; -} - -int32_t AudioMixerManagerMac::StereoRecordingIsAvailable(bool& available) -{ - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - available = (_noInputChannels == 2); - return 0; -} - -int32_t AudioMixerManagerMac::MicrophoneMuteIsAvailable(bool& available) -{ - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - OSStatus err = noErr; - - // Does the capture device have a master mute control? - // If so, use it exclusively. - AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, - kAudioDevicePropertyScopeInput, 0 }; - Boolean isSettable = false; - err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, + // Otherwise try to set each channel. + for (UInt32 i = 1; i <= _noOutputChannels; i++) { + propertyAddress.mElement = i; + isSettable = false; + err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, &isSettable); - if (err == noErr && isSettable) - { - available = true; - return 0; - } - - // Otherwise try to set each channel. - for (UInt32 i = 1; i <= _noInputChannels; i++) - { - propertyAddress.mElement = i; - isSettable = false; - err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, - &isSettable); - if (err != noErr || !isSettable) - { - available = false; - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Mute cannot be set for output channel %d, err=%d", - i, err); - return -1; - } - } - + if (err == noErr && isSettable) { + size = sizeof(mute); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, size, &mute)); + } + success = true; + } + + if (!success) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Unable to set mute on any input channel"); + return -1; + } + + return 0; +} + +int32_t AudioMixerManagerMac::SpeakerMute(bool& enabled) const { + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + UInt32 size = 0; + unsigned int channels = 0; + UInt32 channelMuted = 0; + UInt32 muted = 0; + + // Does the device have a master volume control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, 0}; + Boolean hasProperty = + AudioObjectHasProperty(_outputDeviceID, &propertyAddress); + if (hasProperty) { + size = sizeof(muted); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &muted)); + + // 1 means muted + enabled = static_cast<bool>(muted); + } else { + // Otherwise check if all channels are muted. + for (UInt32 i = 1; i <= _noOutputChannels; i++) { + muted = 0; + propertyAddress.mElement = i; + hasProperty = AudioObjectHasProperty(_outputDeviceID, &propertyAddress); + if (hasProperty) { + size = sizeof(channelMuted); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &channelMuted)); + + muted = (muted && channelMuted); + channels++; + } + } + + if (channels == 0) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Unable to get mute for any channel"); + return -1; + } + + assert(channels > 0); + // 1 means muted + enabled = static_cast<bool>(muted); + } + + WEBRTC_TRACE( + kTraceInfo, kTraceAudioDevice, _id, + " AudioMixerManagerMac::SpeakerMute() => enabled=%d, enabled"); + + return 0; +} + +int32_t AudioMixerManagerMac::StereoPlayoutIsAvailable(bool& available) { + if (_outputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + available = (_noOutputChannels == 2); + return 0; +} + +int32_t AudioMixerManagerMac::StereoRecordingIsAvailable(bool& available) { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + available = (_noInputChannels == 2); + return 0; +} + +int32_t AudioMixerManagerMac::MicrophoneMuteIsAvailable(bool& available) { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + + // Does the capture device have a master mute control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyMute, kAudioDevicePropertyScopeInput, 0}; + Boolean isSettable = false; + err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, + &isSettable); + if (err == noErr && isSettable) { available = true; return 0; -} + } -int32_t AudioMixerManagerMac::SetMicrophoneMute(bool enable) -{ - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "AudioMixerManagerMac::SetMicrophoneMute(enable=%u)", enable); - - CriticalSectionScoped lock(&_critSect); - - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - OSStatus err = noErr; - UInt32 size = 0; - UInt32 mute = enable ? 1 : 0; - bool success = false; - - // Does the capture device have a master mute control? - // If so, use it exclusively. - AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, - kAudioDevicePropertyScopeInput, 0 }; - Boolean isSettable = false; + // Otherwise try to set each channel. + for (UInt32 i = 1; i <= _noInputChannels; i++) { + propertyAddress.mElement = i; + isSettable = false; err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, &isSettable); - if (err == noErr && isSettable) - { - size = sizeof(mute); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, size, &mute)); - - return 0; - } - - // Otherwise try to set each channel. - for (UInt32 i = 1; i <= _noInputChannels; i++) - { - propertyAddress.mElement = i; - isSettable = false; - err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, - &isSettable); - if (err == noErr && isSettable) - { - size = sizeof(mute); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, size, &mute)); - } - success = true; - } - - if (!success) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Unable to set mute on any input channel"); - return -1; - } - - return 0; -} - -int32_t AudioMixerManagerMac::MicrophoneMute(bool& enabled) const -{ - - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - OSStatus err = noErr; - UInt32 size = 0; - unsigned int channels = 0; - UInt32 channelMuted = 0; - UInt32 muted = 0; - - // Does the device have a master volume control? - // If so, use it exclusively. - AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, - kAudioDevicePropertyScopeInput, 0 }; - Boolean hasProperty = AudioObjectHasProperty(_inputDeviceID, - &propertyAddress); - if (hasProperty) - { - size = sizeof(muted); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &muted)); - - // 1 means muted - enabled = static_cast<bool> (muted); - } else - { - // Otherwise check if all channels are muted. - for (UInt32 i = 1; i <= _noInputChannels; i++) - { - muted = 0; - propertyAddress.mElement = i; - hasProperty = AudioObjectHasProperty(_inputDeviceID, - &propertyAddress); - if (hasProperty) - { - size = sizeof(channelMuted); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &channelMuted)); - - muted = (muted && channelMuted); - channels++; - } - } - - if (channels == 0) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Unable to get mute for any channel"); - return -1; - } - - assert(channels > 0); - // 1 means muted - enabled = static_cast<bool> (muted); - } - - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " AudioMixerManagerMac::MicrophoneMute() => enabled=%d", - enabled); + if (err != noErr || !isSettable) { + available = false; + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Mute cannot be set for output channel %d, err=%d", i, err); + return -1; + } + } + + available = true; + return 0; +} + +int32_t AudioMixerManagerMac::SetMicrophoneMute(bool enable) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "AudioMixerManagerMac::SetMicrophoneMute(enable=%u)", enable); + + CriticalSectionScoped lock(&_critSect); + + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + UInt32 size = 0; + UInt32 mute = enable ? 1 : 0; + bool success = false; + + // Does the capture device have a master mute control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyMute, kAudioDevicePropertyScopeInput, 0}; + Boolean isSettable = false; + err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, + &isSettable); + if (err == noErr && isSettable) { + size = sizeof(mute); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, size, &mute)); return 0; -} - -int32_t AudioMixerManagerMac::MicrophoneBoostIsAvailable(bool& available) -{ - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - available = false; // No AudioObjectPropertySelector value for Mic Boost + } - return 0; -} - -int32_t AudioMixerManagerMac::SetMicrophoneBoost(bool enable) -{ - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "AudioMixerManagerMac::SetMicrophoneBoost(enable=%u)", enable); - - CriticalSectionScoped lock(&_critSect); - - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - // Ensure that the selected microphone has a valid boost control. - bool available(false); - MicrophoneBoostIsAvailable(available); - if (!available) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " it is not possible to enable microphone boost"); - return -1; - } - - // It is assumed that the call above fails! - return 0; -} - -int32_t AudioMixerManagerMac::MicrophoneBoost(bool& enabled) const -{ - - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - // Microphone boost cannot be enabled on this platform! - enabled = false; - - return 0; -} - -int32_t AudioMixerManagerMac::MicrophoneVolumeIsAvailable(bool& available) -{ - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - OSStatus err = noErr; - - // Does the capture device have a master volume control? - // If so, use it exclusively. - AudioObjectPropertyAddress - propertyAddress = { kAudioDevicePropertyVolumeScalar, - kAudioDevicePropertyScopeInput, 0 }; - Boolean isSettable = false; + // Otherwise try to set each channel. + for (UInt32 i = 1; i <= _noInputChannels; i++) { + propertyAddress.mElement = i; + isSettable = false; err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, &isSettable); - if (err == noErr && isSettable) - { - available = true; - return 0; - } - - // Otherwise try to set each channel. - for (UInt32 i = 1; i <= _noInputChannels; i++) - { - propertyAddress.mElement = i; - isSettable = false; - err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, - &isSettable); - if (err != noErr || !isSettable) - { - available = false; - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Volume cannot be set for input channel %d, err=%d", - i, err); - return -1; - } - } - + if (err == noErr && isSettable) { + size = sizeof(mute); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, size, &mute)); + } + success = true; + } + + if (!success) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Unable to set mute on any input channel"); + return -1; + } + + return 0; +} + +int32_t AudioMixerManagerMac::MicrophoneMute(bool& enabled) const { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + UInt32 size = 0; + unsigned int channels = 0; + UInt32 channelMuted = 0; + UInt32 muted = 0; + + // Does the device have a master volume control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyMute, kAudioDevicePropertyScopeInput, 0}; + Boolean hasProperty = + AudioObjectHasProperty(_inputDeviceID, &propertyAddress); + if (hasProperty) { + size = sizeof(muted); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &muted)); + + // 1 means muted + enabled = static_cast<bool>(muted); + } else { + // Otherwise check if all channels are muted. + for (UInt32 i = 1; i <= _noInputChannels; i++) { + muted = 0; + propertyAddress.mElement = i; + hasProperty = AudioObjectHasProperty(_inputDeviceID, &propertyAddress); + if (hasProperty) { + size = sizeof(channelMuted); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &channelMuted)); + + muted = (muted && channelMuted); + channels++; + } + } + + if (channels == 0) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Unable to get mute for any channel"); + return -1; + } + + assert(channels > 0); + // 1 means muted + enabled = static_cast<bool>(muted); + } + + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " AudioMixerManagerMac::MicrophoneMute() => enabled=%d", + enabled); + + return 0; +} + +int32_t AudioMixerManagerMac::MicrophoneBoostIsAvailable(bool& available) { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + available = false; // No AudioObjectPropertySelector value for Mic Boost + + return 0; +} + +int32_t AudioMixerManagerMac::SetMicrophoneBoost(bool enable) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "AudioMixerManagerMac::SetMicrophoneBoost(enable=%u)", enable); + + CriticalSectionScoped lock(&_critSect); + + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + // Ensure that the selected microphone has a valid boost control. + bool available(false); + MicrophoneBoostIsAvailable(available); + if (!available) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " it is not possible to enable microphone boost"); + return -1; + } + + // It is assumed that the call above fails! + return 0; +} + +int32_t AudioMixerManagerMac::MicrophoneBoost(bool& enabled) const { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + // Microphone boost cannot be enabled on this platform! + enabled = false; + + return 0; +} + +int32_t AudioMixerManagerMac::MicrophoneVolumeIsAvailable(bool& available) { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + + // Does the capture device have a master volume control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput, 0}; + Boolean isSettable = false; + err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, + &isSettable); + if (err == noErr && isSettable) { available = true; return 0; -} - -int32_t AudioMixerManagerMac::SetMicrophoneVolume(uint32_t volume) -{ - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "AudioMixerManagerMac::SetMicrophoneVolume(volume=%u)", volume); - - CriticalSectionScoped lock(&_critSect); + } - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - OSStatus err = noErr; - UInt32 size = 0; - bool success = false; - - // volume range is 0.0 - 1.0, convert from 0 - 255 - const Float32 vol = (Float32)(volume / 255.0); - - assert(vol <= 1.0 && vol >= 0.0); - - // Does the capture device have a master volume control? - // If so, use it exclusively. - AudioObjectPropertyAddress - propertyAddress = { kAudioDevicePropertyVolumeScalar, - kAudioDevicePropertyScopeInput, 0 }; - Boolean isSettable = false; + // Otherwise try to set each channel. + for (UInt32 i = 1; i <= _noInputChannels; i++) { + propertyAddress.mElement = i; + isSettable = false; err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, &isSettable); - if (err == noErr && isSettable) - { - size = sizeof(vol); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, size, &vol)); - - return 0; + if (err != noErr || !isSettable) { + available = false; + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Volume cannot be set for input channel %d, err=%d", i, + err); + return -1; } + } - // Otherwise try to set each channel. - for (UInt32 i = 1; i <= _noInputChannels; i++) - { - propertyAddress.mElement = i; - isSettable = false; - err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, - &isSettable); - if (err == noErr && isSettable) - { - size = sizeof(vol); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, size, &vol)); - } - success = true; - } - - if (!success) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Unable to set a level on any input channel"); - return -1; - } - - return 0; + available = true; + return 0; } -int32_t -AudioMixerManagerMac::MicrophoneVolume(uint32_t& volume) const -{ - - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } +int32_t AudioMixerManagerMac::SetMicrophoneVolume(uint32_t volume) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "AudioMixerManagerMac::SetMicrophoneVolume(volume=%u)", volume); - OSStatus err = noErr; - UInt32 size = 0; - unsigned int channels = 0; - Float32 channelVol = 0; - Float32 volFloat32 = 0; - - // Does the device have a master volume control? - // If so, use it exclusively. - AudioObjectPropertyAddress - propertyAddress = { kAudioDevicePropertyVolumeScalar, - kAudioDevicePropertyScopeInput, 0 }; - Boolean hasProperty = AudioObjectHasProperty(_inputDeviceID, - &propertyAddress); - if (hasProperty) - { - size = sizeof(volFloat32); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &volFloat32)); - - // vol 0.0 to 1.0 -> convert to 0 - 255 - volume = static_cast<uint32_t> (volFloat32 * 255 + 0.5); - } else - { - // Otherwise get the average volume across channels. - volFloat32 = 0; - for (UInt32 i = 1; i <= _noInputChannels; i++) - { - channelVol = 0; - propertyAddress.mElement = i; - hasProperty = AudioObjectHasProperty(_inputDeviceID, - &propertyAddress); - if (hasProperty) - { - size = sizeof(channelVol); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &channelVol)); - - volFloat32 += channelVol; - channels++; - } - } - - if (channels == 0) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Unable to get a level on any channel"); - return -1; - } - - assert(channels > 0); - // vol 0.0 to 1.0 -> convert to 0 - 255 - volume = static_cast<uint32_t> - (255 * volFloat32 / channels + 0.5); - } + CriticalSectionScoped lock(&_critSect); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " AudioMixerManagerMac::MicrophoneVolume() => vol=%u", - volume); + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } - return 0; -} + OSStatus err = noErr; + UInt32 size = 0; + bool success = false; -int32_t -AudioMixerManagerMac::MaxMicrophoneVolume(uint32_t& maxVolume) const -{ + // volume range is 0.0 - 1.0, convert from 0 - 255 + const Float32 vol = (Float32)(volume / 255.0); - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } + assert(vol <= 1.0 && vol >= 0.0); - // volume range is 0.0 to 1.0 - // we convert that to 0 - 255 - maxVolume = 255; + // Does the capture device have a master volume control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput, 0}; + Boolean isSettable = false; + err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, + &isSettable); + if (err == noErr && isSettable) { + size = sizeof(vol); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, size, &vol)); return 0; -} - -int32_t -AudioMixerManagerMac::MinMicrophoneVolume(uint32_t& minVolume) const -{ - - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } + } - // volume range is 0.0 to 1.0 - // we convert that to 0 - 10 - minVolume = 0; + // Otherwise try to set each channel. + for (UInt32 i = 1; i <= _noInputChannels; i++) { + propertyAddress.mElement = i; + isSettable = false; + err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, + &isSettable); + if (err == noErr && isSettable) { + size = sizeof(vol); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, size, &vol)); + } + success = true; + } + + if (!success) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Unable to set a level on any input channel"); + return -1; + } + + return 0; +} + +int32_t AudioMixerManagerMac::MicrophoneVolume(uint32_t& volume) const { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + OSStatus err = noErr; + UInt32 size = 0; + unsigned int channels = 0; + Float32 channelVol = 0; + Float32 volFloat32 = 0; + + // Does the device have a master volume control? + // If so, use it exclusively. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput, 0}; + Boolean hasProperty = + AudioObjectHasProperty(_inputDeviceID, &propertyAddress); + if (hasProperty) { + size = sizeof(volFloat32); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &volFloat32)); + + // vol 0.0 to 1.0 -> convert to 0 - 255 + volume = static_cast<uint32_t>(volFloat32 * 255 + 0.5); + } else { + // Otherwise get the average volume across channels. + volFloat32 = 0; + for (UInt32 i = 1; i <= _noInputChannels; i++) { + channelVol = 0; + propertyAddress.mElement = i; + hasProperty = AudioObjectHasProperty(_inputDeviceID, &propertyAddress); + if (hasProperty) { + size = sizeof(channelVol); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &channelVol)); + + volFloat32 += channelVol; + channels++; + } + } + + if (channels == 0) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Unable to get a level on any channel"); + return -1; + } + + assert(channels > 0); + // vol 0.0 to 1.0 -> convert to 0 - 255 + volume = static_cast<uint32_t>(255 * volFloat32 / channels + 0.5); + } + + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " AudioMixerManagerMac::MicrophoneVolume() => vol=%u", + volume); + + return 0; +} + +int32_t AudioMixerManagerMac::MaxMicrophoneVolume(uint32_t& maxVolume) const { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + // volume range is 0.0 to 1.0 + // we convert that to 0 - 255 + maxVolume = 255; + + return 0; +} + +int32_t AudioMixerManagerMac::MinMicrophoneVolume(uint32_t& minVolume) const { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + // volume range is 0.0 to 1.0 + // we convert that to 0 - 10 + minVolume = 0; - return 0; + return 0; } -int32_t -AudioMixerManagerMac::MicrophoneVolumeStepSize(uint16_t& stepSize) const -{ - - if (_inputDeviceID == kAudioObjectUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " device ID has not been set"); - return -1; - } - - // volume range is 0.0 to 1.0 - // we convert that to 0 - 10 - stepSize = 1; - - return 0; +int32_t AudioMixerManagerMac::MicrophoneVolumeStepSize( + uint16_t& stepSize) const { + if (_inputDeviceID == kAudioObjectUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " device ID has not been set"); + return -1; + } + + // volume range is 0.0 to 1.0 + // we convert that to 0 - 10 + stepSize = 1; + + return 0; } // ============================================================================ @@ -1148,18 +1003,18 @@ AudioMixerManagerMac::MicrophoneVolumeStepSize(uint16_t& stepSize) const // CoreAudio errors are best interpreted as four character strings. void AudioMixerManagerMac::logCAMsg(const TraceLevel level, const TraceModule module, - const int32_t id, const char *msg, - const char *err) -{ - assert(msg != NULL); - assert(err != NULL); + const int32_t id, + const char* msg, + const char* err) { + assert(msg != NULL); + assert(err != NULL); #ifdef WEBRTC_ARCH_BIG_ENDIAN - WEBRTC_TRACE(level, module, id, "%s: %.4s", msg, err); + WEBRTC_TRACE(level, module, id, "%s: %.4s", msg, err); #else - // We need to flip the characters in this case. - WEBRTC_TRACE(level, module, id, "%s: %.1s%.1s%.1s%.1s", msg, err + 3, err - + 2, err + 1, err); + // We need to flip the characters in this case. + WEBRTC_TRACE(level, module, id, "%s: %.1s%.1s%.1s%.1s", msg, err + 3, err + 2, + err + 1, err); #endif } |