diff options
author | andrew <andrew@webrtc.org> | 2016-01-11 15:59:17 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-11 23:59:25 +0000 |
commit | 2bc63a1dd3188402f4da1cdb6ed24fc058819304 (patch) | |
tree | 620c9452740c785784b6b5158ec42ff4fecb8976 | |
parent | a7446d2a50167602b04f58c917f5075ad5e494dc (diff) | |
download | webrtc-2bc63a1dd3188402f4da1cdb6ed24fc058819304.tar.gz |
clang-format audio_device/mac.
NOTRY=true
Review URL: https://codereview.webrtc.org/1570063003
Cr-Commit-Position: refs/heads/master@{#11212}
-rw-r--r-- | webrtc/modules/audio_device/mac/audio_device_mac.cc | 4845 | ||||
-rw-r--r-- | webrtc/modules/audio_device/mac/audio_device_mac.h | 572 | ||||
-rw-r--r-- | webrtc/modules/audio_device/mac/audio_mixer_manager_mac.cc | 1907 | ||||
-rw-r--r-- | webrtc/modules/audio_device/mac/audio_mixer_manager_mac.h | 99 |
4 files changed, 3398 insertions, 4025 deletions
diff --git a/webrtc/modules/audio_device/mac/audio_device_mac.cc b/webrtc/modules/audio_device/mac/audio_device_mac.cc index d963f2b7f2..0f33d1124d 100644 --- a/webrtc/modules/audio_device/mac/audio_device_mac.cc +++ b/webrtc/modules/audio_device/mac/audio_device_mac.cc @@ -18,3227 +18,2750 @@ #include "webrtc/system_wrappers/include/trace.h" #include <ApplicationServices/ApplicationServices.h> -#include <libkern/OSAtomic.h> // OSAtomicCompareAndSwap() -#include <mach/mach.h> // mach_task_self() -#include <sys/sysctl.h> // sysctlbyname() - - - -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) - -enum -{ - MaxNumberDevices = 64 -}; - -void AudioDeviceMac::AtomicSet32(int32_t* theValue, int32_t newValue) -{ - while (1) - { - int32_t oldValue = *theValue; - if (OSAtomicCompareAndSwap32Barrier(oldValue, newValue, theValue) - == true) - { - return; - } +#include <libkern/OSAtomic.h> // OSAtomicCompareAndSwap() +#include <mach/mach.h> // mach_task_self() +#include <sys/sysctl.h> // sysctlbyname() + +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) + +enum { MaxNumberDevices = 64 }; + +void AudioDeviceMac::AtomicSet32(int32_t* theValue, int32_t newValue) { + while (1) { + int32_t oldValue = *theValue; + if (OSAtomicCompareAndSwap32Barrier(oldValue, newValue, theValue) == true) { + return; } + } } -int32_t AudioDeviceMac::AtomicGet32(int32_t* theValue) -{ - while (1) - { - int32_t value = *theValue; - if (OSAtomicCompareAndSwap32Barrier(value, value, theValue) == true) - { - return value; - } +int32_t AudioDeviceMac::AtomicGet32(int32_t* theValue) { + while (1) { + int32_t value = *theValue; + if (OSAtomicCompareAndSwap32Barrier(value, value, theValue) == true) { + return value; } + } } // CoreAudio errors are best interpreted as four character strings. void AudioDeviceMac::logCAMsg(const TraceLevel level, const TraceModule module, - const int32_t id, const char *msg, - const char *err) -{ + const int32_t id, + const char* msg, + const char* err) { RTC_DCHECK(msg != NULL); RTC_DCHECK(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 } -AudioDeviceMac::AudioDeviceMac(const int32_t id) : - _ptrAudioBuffer(NULL), - _critSect(*CriticalSectionWrapper::CreateCriticalSection()), - _stopEventRec(*EventWrapper::Create()), - _stopEvent(*EventWrapper::Create()), - _id(id), - _mixerManager(id), - _inputDeviceIndex(0), - _outputDeviceIndex(0), - _inputDeviceID(kAudioObjectUnknown), - _outputDeviceID(kAudioObjectUnknown), - _inputDeviceIsSpecified(false), - _outputDeviceIsSpecified(false), - _recChannels(N_REC_CHANNELS), - _playChannels(N_PLAY_CHANNELS), - _captureBufData(NULL), - _renderBufData(NULL), - _playBufType(AudioDeviceModule::kFixedBufferSize), - _initialized(false), - _isShutDown(false), - _recording(false), - _playing(false), - _recIsInitialized(false), - _playIsInitialized(false), - _AGC(false), - _renderDeviceIsAlive(1), - _captureDeviceIsAlive(1), - _twoDevices(true), - _doStop(false), - _doStopRec(false), - _macBookPro(false), - _macBookProPanRight(false), - _captureLatencyUs(0), - _renderLatencyUs(0), - _captureDelayUs(0), - _renderDelayUs(0), - _renderDelayOffsetSamples(0), - _playBufDelayFixed(20), - _playWarning(0), - _playError(0), - _recWarning(0), - _recError(0), - _paCaptureBuffer(NULL), - _paRenderBuffer(NULL), - _captureBufSizeSamples(0), - _renderBufSizeSamples(0), - prev_key_state_(), - get_mic_volume_counter_ms_(0) -{ - WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id, - "%s created", __FUNCTION__); - - RTC_DCHECK(&_stopEvent != NULL); - RTC_DCHECK(&_stopEventRec != NULL); - - memset(_renderConvertData, 0, sizeof(_renderConvertData)); - memset(&_outStreamFormat, 0, sizeof(AudioStreamBasicDescription)); - memset(&_outDesiredFormat, 0, sizeof(AudioStreamBasicDescription)); - memset(&_inStreamFormat, 0, sizeof(AudioStreamBasicDescription)); - memset(&_inDesiredFormat, 0, sizeof(AudioStreamBasicDescription)); -} - - -AudioDeviceMac::~AudioDeviceMac() -{ - WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, - "%s destroyed", __FUNCTION__); - - if (!_isShutDown) - { - Terminate(); - } +AudioDeviceMac::AudioDeviceMac(const int32_t id) + : _ptrAudioBuffer(NULL), + _critSect(*CriticalSectionWrapper::CreateCriticalSection()), + _stopEventRec(*EventWrapper::Create()), + _stopEvent(*EventWrapper::Create()), + _id(id), + _mixerManager(id), + _inputDeviceIndex(0), + _outputDeviceIndex(0), + _inputDeviceID(kAudioObjectUnknown), + _outputDeviceID(kAudioObjectUnknown), + _inputDeviceIsSpecified(false), + _outputDeviceIsSpecified(false), + _recChannels(N_REC_CHANNELS), + _playChannels(N_PLAY_CHANNELS), + _captureBufData(NULL), + _renderBufData(NULL), + _playBufType(AudioDeviceModule::kFixedBufferSize), + _initialized(false), + _isShutDown(false), + _recording(false), + _playing(false), + _recIsInitialized(false), + _playIsInitialized(false), + _AGC(false), + _renderDeviceIsAlive(1), + _captureDeviceIsAlive(1), + _twoDevices(true), + _doStop(false), + _doStopRec(false), + _macBookPro(false), + _macBookProPanRight(false), + _captureLatencyUs(0), + _renderLatencyUs(0), + _captureDelayUs(0), + _renderDelayUs(0), + _renderDelayOffsetSamples(0), + _playBufDelayFixed(20), + _playWarning(0), + _playError(0), + _recWarning(0), + _recError(0), + _paCaptureBuffer(NULL), + _paRenderBuffer(NULL), + _captureBufSizeSamples(0), + _renderBufSizeSamples(0), + prev_key_state_(), + get_mic_volume_counter_ms_(0) { + WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id, "%s created", __FUNCTION__); + + RTC_DCHECK(&_stopEvent != NULL); + RTC_DCHECK(&_stopEventRec != NULL); + + memset(_renderConvertData, 0, sizeof(_renderConvertData)); + memset(&_outStreamFormat, 0, sizeof(AudioStreamBasicDescription)); + memset(&_outDesiredFormat, 0, sizeof(AudioStreamBasicDescription)); + memset(&_inStreamFormat, 0, sizeof(AudioStreamBasicDescription)); + memset(&_inDesiredFormat, 0, sizeof(AudioStreamBasicDescription)); +} + +AudioDeviceMac::~AudioDeviceMac() { + WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destroyed", + __FUNCTION__); + + if (!_isShutDown) { + Terminate(); + } - RTC_DCHECK(!capture_worker_thread_.get()); - RTC_DCHECK(!render_worker_thread_.get()); + RTC_DCHECK(!capture_worker_thread_.get()); + RTC_DCHECK(!render_worker_thread_.get()); - if (_paRenderBuffer) - { - delete _paRenderBuffer; - _paRenderBuffer = NULL; - } + if (_paRenderBuffer) { + delete _paRenderBuffer; + _paRenderBuffer = NULL; + } - if (_paCaptureBuffer) - { - delete _paCaptureBuffer; - _paCaptureBuffer = NULL; - } + if (_paCaptureBuffer) { + delete _paCaptureBuffer; + _paCaptureBuffer = NULL; + } - if (_renderBufData) - { - delete[] _renderBufData; - _renderBufData = NULL; - } + if (_renderBufData) { + delete[] _renderBufData; + _renderBufData = NULL; + } - if (_captureBufData) - { - delete[] _captureBufData; - _captureBufData = NULL; - } + if (_captureBufData) { + delete[] _captureBufData; + _captureBufData = NULL; + } - kern_return_t kernErr = KERN_SUCCESS; - kernErr = semaphore_destroy(mach_task_self(), _renderSemaphore); - if (kernErr != KERN_SUCCESS) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " semaphore_destroy() error: %d", kernErr); - } + kern_return_t kernErr = KERN_SUCCESS; + kernErr = semaphore_destroy(mach_task_self(), _renderSemaphore); + if (kernErr != KERN_SUCCESS) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " semaphore_destroy() error: %d", kernErr); + } - kernErr = semaphore_destroy(mach_task_self(), _captureSemaphore); - if (kernErr != KERN_SUCCESS) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " semaphore_destroy() error: %d", kernErr); - } + kernErr = semaphore_destroy(mach_task_self(), _captureSemaphore); + if (kernErr != KERN_SUCCESS) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " semaphore_destroy() error: %d", kernErr); + } - delete &_stopEvent; - delete &_stopEventRec; - delete &_critSect; + delete &_stopEvent; + delete &_stopEventRec; + delete &_critSect; } // ============================================================================ // API // ============================================================================ -void AudioDeviceMac::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) -{ +void AudioDeviceMac::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) { + CriticalSectionScoped lock(&_critSect); - CriticalSectionScoped lock(&_critSect); + _ptrAudioBuffer = audioBuffer; - _ptrAudioBuffer = audioBuffer; - - // inform the AudioBuffer about default settings for this implementation - _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); - _ptrAudioBuffer->SetPlayoutSampleRate(N_PLAY_SAMPLES_PER_SEC); - _ptrAudioBuffer->SetRecordingChannels(N_REC_CHANNELS); - _ptrAudioBuffer->SetPlayoutChannels(N_PLAY_CHANNELS); + // inform the AudioBuffer about default settings for this implementation + _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); + _ptrAudioBuffer->SetPlayoutSampleRate(N_PLAY_SAMPLES_PER_SEC); + _ptrAudioBuffer->SetRecordingChannels(N_REC_CHANNELS); + _ptrAudioBuffer->SetPlayoutChannels(N_PLAY_CHANNELS); } int32_t AudioDeviceMac::ActiveAudioLayer( - AudioDeviceModule::AudioLayer& audioLayer) const -{ - audioLayer = AudioDeviceModule::kPlatformDefaultAudio; - return 0; + AudioDeviceModule::AudioLayer& audioLayer) const { + audioLayer = AudioDeviceModule::kPlatformDefaultAudio; + return 0; } -int32_t AudioDeviceMac::Init() -{ +int32_t AudioDeviceMac::Init() { + CriticalSectionScoped lock(&_critSect); - CriticalSectionScoped lock(&_critSect); + if (_initialized) { + return 0; + } - if (_initialized) - { - return 0; - } + OSStatus err = noErr; - OSStatus err = noErr; + _isShutDown = false; - _isShutDown = false; - - // PortAudio ring buffers require an elementCount which is a power of two. - if (_renderBufData == NULL) - { - UInt32 powerOfTwo = 1; - while (powerOfTwo < PLAY_BUF_SIZE_IN_SAMPLES) - { - powerOfTwo <<= 1; - } - _renderBufSizeSamples = powerOfTwo; - _renderBufData = new SInt16[_renderBufSizeSamples]; + // PortAudio ring buffers require an elementCount which is a power of two. + if (_renderBufData == NULL) { + UInt32 powerOfTwo = 1; + while (powerOfTwo < PLAY_BUF_SIZE_IN_SAMPLES) { + powerOfTwo <<= 1; } + _renderBufSizeSamples = powerOfTwo; + _renderBufData = new SInt16[_renderBufSizeSamples]; + } - if (_paRenderBuffer == NULL) - { - _paRenderBuffer = new PaUtilRingBuffer; - PaRingBufferSize bufSize = -1; - bufSize = PaUtil_InitializeRingBuffer(_paRenderBuffer, sizeof(SInt16), - _renderBufSizeSamples, - _renderBufData); - if (bufSize == -1) - { - WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, - _id, " PaUtil_InitializeRingBuffer() error"); - return -1; - } + if (_paRenderBuffer == NULL) { + _paRenderBuffer = new PaUtilRingBuffer; + PaRingBufferSize bufSize = -1; + bufSize = PaUtil_InitializeRingBuffer( + _paRenderBuffer, sizeof(SInt16), _renderBufSizeSamples, _renderBufData); + if (bufSize == -1) { + WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, + " PaUtil_InitializeRingBuffer() error"); + return -1; } + } - if (_captureBufData == NULL) - { - UInt32 powerOfTwo = 1; - while (powerOfTwo < REC_BUF_SIZE_IN_SAMPLES) - { - powerOfTwo <<= 1; - } - _captureBufSizeSamples = powerOfTwo; - _captureBufData = new Float32[_captureBufSizeSamples]; + if (_captureBufData == NULL) { + UInt32 powerOfTwo = 1; + while (powerOfTwo < REC_BUF_SIZE_IN_SAMPLES) { + powerOfTwo <<= 1; } + _captureBufSizeSamples = powerOfTwo; + _captureBufData = new Float32[_captureBufSizeSamples]; + } - if (_paCaptureBuffer == NULL) - { - _paCaptureBuffer = new PaUtilRingBuffer; - PaRingBufferSize bufSize = -1; - bufSize = PaUtil_InitializeRingBuffer(_paCaptureBuffer, - sizeof(Float32), - _captureBufSizeSamples, - _captureBufData); - if (bufSize == -1) - { - WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, - _id, " PaUtil_InitializeRingBuffer() error"); - return -1; - } + if (_paCaptureBuffer == NULL) { + _paCaptureBuffer = new PaUtilRingBuffer; + PaRingBufferSize bufSize = -1; + bufSize = + PaUtil_InitializeRingBuffer(_paCaptureBuffer, sizeof(Float32), + _captureBufSizeSamples, _captureBufData); + if (bufSize == -1) { + WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, + " PaUtil_InitializeRingBuffer() error"); + return -1; } + } - kern_return_t kernErr = KERN_SUCCESS; - kernErr = semaphore_create(mach_task_self(), &_renderSemaphore, - SYNC_POLICY_FIFO, 0); - if (kernErr != KERN_SUCCESS) - { - WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, - " semaphore_create() error: %d", kernErr); - return -1; - } + kern_return_t kernErr = KERN_SUCCESS; + kernErr = semaphore_create(mach_task_self(), &_renderSemaphore, + SYNC_POLICY_FIFO, 0); + if (kernErr != KERN_SUCCESS) { + WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, + " semaphore_create() error: %d", kernErr); + return -1; + } - kernErr = semaphore_create(mach_task_self(), &_captureSemaphore, - SYNC_POLICY_FIFO, 0); - if (kernErr != KERN_SUCCESS) - { - WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, - " semaphore_create() error: %d", kernErr); - return -1; - } + kernErr = semaphore_create(mach_task_self(), &_captureSemaphore, + SYNC_POLICY_FIFO, 0); + if (kernErr != KERN_SUCCESS) { + WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, + " semaphore_create() error: %d", kernErr); + return -1; + } - // Setting RunLoop to NULL here instructs HAL to manage its own thread for - // notifications. This was the default behaviour on OS X 10.5 and earlier, - // but now must be explicitly specified. HAL would otherwise try to use the - // main thread to issue notifications. - AudioObjectPropertyAddress propertyAddress = { - kAudioHardwarePropertyRunLoop, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster }; - CFRunLoopRef runLoop = NULL; - UInt32 size = sizeof(CFRunLoopRef); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(kAudioObjectSystemObject, - &propertyAddress, 0, NULL, size, &runLoop)); - - // Listen for any device changes. - propertyAddress.mSelector = kAudioHardwarePropertyDevices; - WEBRTC_CA_LOG_ERR(AudioObjectAddPropertyListener(kAudioObjectSystemObject, - &propertyAddress, &objectListenerProc, this)); - - // Determine if this is a MacBook Pro - _macBookPro = false; - _macBookProPanRight = false; - char buf[128]; - size_t length = sizeof(buf); - memset(buf, 0, length); - - int intErr = sysctlbyname("hw.model", buf, &length, NULL, 0); - if (intErr != 0) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " Error in sysctlbyname(): %d", err); - } else - { - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " Hardware model: %s", buf); - if (strncmp(buf, "MacBookPro", 10) == 0) - { - _macBookPro = true; - } + // Setting RunLoop to NULL here instructs HAL to manage its own thread for + // notifications. This was the default behaviour on OS X 10.5 and earlier, + // but now must be explicitly specified. HAL would otherwise try to use the + // main thread to issue notifications. + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster}; + CFRunLoopRef runLoop = NULL; + UInt32 size = sizeof(CFRunLoopRef); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + kAudioObjectSystemObject, &propertyAddress, 0, NULL, size, &runLoop)); + + // Listen for any device changes. + propertyAddress.mSelector = kAudioHardwarePropertyDevices; + WEBRTC_CA_LOG_ERR(AudioObjectAddPropertyListener( + kAudioObjectSystemObject, &propertyAddress, &objectListenerProc, this)); + + // Determine if this is a MacBook Pro + _macBookPro = false; + _macBookProPanRight = false; + char buf[128]; + size_t length = sizeof(buf); + memset(buf, 0, length); + + int intErr = sysctlbyname("hw.model", buf, &length, NULL, 0); + if (intErr != 0) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " Error in sysctlbyname(): %d", err); + } else { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " Hardware model: %s", + buf); + if (strncmp(buf, "MacBookPro", 10) == 0) { + _macBookPro = true; } + } - _playWarning = 0; - _playError = 0; - _recWarning = 0; - _recError = 0; + _playWarning = 0; + _playError = 0; + _recWarning = 0; + _recError = 0; - get_mic_volume_counter_ms_ = 0; + get_mic_volume_counter_ms_ = 0; - _initialized = true; + _initialized = true; - return 0; + return 0; } -int32_t AudioDeviceMac::Terminate() -{ +int32_t AudioDeviceMac::Terminate() { + if (!_initialized) { + return 0; + } - if (!_initialized) - { - return 0; - } + if (_recording) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " Recording must be stopped"); + return -1; + } - if (_recording) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " Recording must be stopped"); - return -1; - } + if (_playing) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " Playback must be stopped"); + return -1; + } - if (_playing) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " Playback must be stopped"); - return -1; - } + _critSect.Enter(); - _critSect.Enter(); + _mixerManager.Close(); - _mixerManager.Close(); + OSStatus err = noErr; + int retVal = 0; - OSStatus err = noErr; - int retVal = 0; + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster}; + WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener( + kAudioObjectSystemObject, &propertyAddress, &objectListenerProc, this)); - AudioObjectPropertyAddress propertyAddress = { - kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster }; - WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(kAudioObjectSystemObject, - &propertyAddress, &objectListenerProc, this)); - - err = AudioHardwareUnload(); - if (err != noErr) - { - logCAMsg(kTraceError, kTraceAudioDevice, _id, - "Error in AudioHardwareUnload()", (const char*) &err); - retVal = -1; - } + err = AudioHardwareUnload(); + if (err != noErr) { + logCAMsg(kTraceError, kTraceAudioDevice, _id, + "Error in AudioHardwareUnload()", (const char*)&err); + retVal = -1; + } - _isShutDown = true; - _initialized = false; - _outputDeviceIsSpecified = false; - _inputDeviceIsSpecified = false; + _isShutDown = true; + _initialized = false; + _outputDeviceIsSpecified = false; + _inputDeviceIsSpecified = false; - _critSect.Leave(); + _critSect.Leave(); - return retVal; + return retVal; } -bool AudioDeviceMac::Initialized() const -{ - return (_initialized); +bool AudioDeviceMac::Initialized() const { + return (_initialized); } -int32_t AudioDeviceMac::SpeakerIsAvailable(bool& available) -{ - - bool wasInitialized = _mixerManager.SpeakerIsInitialized(); +int32_t AudioDeviceMac::SpeakerIsAvailable(bool& available) { + bool wasInitialized = _mixerManager.SpeakerIsInitialized(); - // Make an attempt to open up the - // output mixer corresponding to the currently selected output device. - // - if (!wasInitialized && InitSpeaker() == -1) - { - available = false; - return 0; - } + // Make an attempt to open up the + // output mixer corresponding to the currently selected output device. + // + if (!wasInitialized && InitSpeaker() == -1) { + available = false; + return 0; + } - // Given that InitSpeaker was successful, we know that a valid speaker - // exists. - available = true; + // Given that InitSpeaker was successful, we know that a valid speaker + // exists. + available = true; - // Close the initialized output mixer - // - if (!wasInitialized) - { - _mixerManager.CloseSpeaker(); - } + // Close the initialized output mixer + // + if (!wasInitialized) { + _mixerManager.CloseSpeaker(); + } - return 0; + return 0; } -int32_t AudioDeviceMac::InitSpeaker() -{ - - CriticalSectionScoped lock(&_critSect); +int32_t AudioDeviceMac::InitSpeaker() { + CriticalSectionScoped lock(&_critSect); - if (_playing) - { - return -1; - } + if (_playing) { + return -1; + } - if (InitDevice(_outputDeviceIndex, _outputDeviceID, false) == -1) - { - return -1; - } + if (InitDevice(_outputDeviceIndex, _outputDeviceID, false) == -1) { + return -1; + } - if (_inputDeviceID == _outputDeviceID) - { - _twoDevices = false; - } else - { - _twoDevices = true; - } + if (_inputDeviceID == _outputDeviceID) { + _twoDevices = false; + } else { + _twoDevices = true; + } - if (_mixerManager.OpenSpeaker(_outputDeviceID) == -1) - { - return -1; - } + if (_mixerManager.OpenSpeaker(_outputDeviceID) == -1) { + return -1; + } - return 0; + return 0; } -int32_t AudioDeviceMac::MicrophoneIsAvailable(bool& available) -{ - - bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); +int32_t AudioDeviceMac::MicrophoneIsAvailable(bool& available) { + bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); - // Make an attempt to open up the - // input mixer corresponding to the currently selected output device. - // - if (!wasInitialized && InitMicrophone() == -1) - { - available = false; - return 0; - } + // Make an attempt to open up the + // input mixer corresponding to the currently selected output device. + // + if (!wasInitialized && InitMicrophone() == -1) { + available = false; + return 0; + } - // Given that InitMicrophone was successful, we know that a valid microphone - // exists. - available = true; + // Given that InitMicrophone was successful, we know that a valid microphone + // exists. + available = true; - // Close the initialized input mixer - // - if (!wasInitialized) - { - _mixerManager.CloseMicrophone(); - } + // Close the initialized input mixer + // + if (!wasInitialized) { + _mixerManager.CloseMicrophone(); + } - return 0; + return 0; } -int32_t AudioDeviceMac::InitMicrophone() -{ +int32_t AudioDeviceMac::InitMicrophone() { + CriticalSectionScoped lock(&_critSect); - CriticalSectionScoped lock(&_critSect); - - if (_recording) - { - return -1; - } + if (_recording) { + return -1; + } - if (InitDevice(_inputDeviceIndex, _inputDeviceID, true) == -1) - { - return -1; - } + if (InitDevice(_inputDeviceIndex, _inputDeviceID, true) == -1) { + return -1; + } - if (_inputDeviceID == _outputDeviceID) - { - _twoDevices = false; - } else - { - _twoDevices = true; - } + if (_inputDeviceID == _outputDeviceID) { + _twoDevices = false; + } else { + _twoDevices = true; + } - if (_mixerManager.OpenMicrophone(_inputDeviceID) == -1) - { - return -1; - } + if (_mixerManager.OpenMicrophone(_inputDeviceID) == -1) { + return -1; + } - return 0; + return 0; } -bool AudioDeviceMac::SpeakerIsInitialized() const -{ - return (_mixerManager.SpeakerIsInitialized()); +bool AudioDeviceMac::SpeakerIsInitialized() const { + return (_mixerManager.SpeakerIsInitialized()); } -bool AudioDeviceMac::MicrophoneIsInitialized() const -{ - return (_mixerManager.MicrophoneIsInitialized()); +bool AudioDeviceMac::MicrophoneIsInitialized() const { + return (_mixerManager.MicrophoneIsInitialized()); } -int32_t AudioDeviceMac::SpeakerVolumeIsAvailable(bool& available) -{ - - bool wasInitialized = _mixerManager.SpeakerIsInitialized(); +int32_t AudioDeviceMac::SpeakerVolumeIsAvailable(bool& available) { + bool wasInitialized = _mixerManager.SpeakerIsInitialized(); - // Make an attempt to open up the - // output mixer corresponding to the currently selected output device. - // - if (!wasInitialized && InitSpeaker() == -1) - { - // If we end up here it means that the selected speaker has no volume - // control. - available = false; - return 0; - } + // Make an attempt to open up the + // output mixer corresponding to the currently selected output device. + // + if (!wasInitialized && InitSpeaker() == -1) { + // If we end up here it means that the selected speaker has no volume + // control. + available = false; + return 0; + } - // Given that InitSpeaker was successful, we know that a volume control exists - // - available = true; + // Given that InitSpeaker was successful, we know that a volume control exists + // + available = true; - // Close the initialized output mixer - // - if (!wasInitialized) - { - _mixerManager.CloseSpeaker(); - } + // Close the initialized output mixer + // + if (!wasInitialized) { + _mixerManager.CloseSpeaker(); + } - return 0; + return 0; } -int32_t AudioDeviceMac::SetSpeakerVolume(uint32_t volume) -{ - - return (_mixerManager.SetSpeakerVolume(volume)); +int32_t AudioDeviceMac::SetSpeakerVolume(uint32_t volume) { + return (_mixerManager.SetSpeakerVolume(volume)); } -int32_t AudioDeviceMac::SpeakerVolume(uint32_t& volume) const -{ - - uint32_t level(0); +int32_t AudioDeviceMac::SpeakerVolume(uint32_t& volume) const { + uint32_t level(0); - if (_mixerManager.SpeakerVolume(level) == -1) - { - return -1; - } + if (_mixerManager.SpeakerVolume(level) == -1) { + return -1; + } - volume = level; - return 0; + volume = level; + return 0; } int32_t AudioDeviceMac::SetWaveOutVolume(uint16_t volumeLeft, - uint16_t volumeRight) -{ - - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " API call not supported on this platform"); - return -1; + uint16_t volumeRight) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " API call not supported on this platform"); + return -1; } -int32_t -AudioDeviceMac::WaveOutVolume(uint16_t& /*volumeLeft*/, - uint16_t& /*volumeRight*/) const -{ - - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " API call not supported on this platform"); - return -1; +int32_t AudioDeviceMac::WaveOutVolume(uint16_t& /*volumeLeft*/, + uint16_t& /*volumeRight*/) const { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " API call not supported on this platform"); + return -1; } -int32_t AudioDeviceMac::MaxSpeakerVolume(uint32_t& maxVolume) const -{ +int32_t AudioDeviceMac::MaxSpeakerVolume(uint32_t& maxVolume) const { + uint32_t maxVol(0); - uint32_t maxVol(0); - - if (_mixerManager.MaxSpeakerVolume(maxVol) == -1) - { - return -1; - } + if (_mixerManager.MaxSpeakerVolume(maxVol) == -1) { + return -1; + } - maxVolume = maxVol; - return 0; + maxVolume = maxVol; + return 0; } -int32_t AudioDeviceMac::MinSpeakerVolume(uint32_t& minVolume) const -{ - - uint32_t minVol(0); +int32_t AudioDeviceMac::MinSpeakerVolume(uint32_t& minVolume) const { + uint32_t minVol(0); - if (_mixerManager.MinSpeakerVolume(minVol) == -1) - { - return -1; - } + if (_mixerManager.MinSpeakerVolume(minVol) == -1) { + return -1; + } - minVolume = minVol; - return 0; + minVolume = minVol; + return 0; } -int32_t -AudioDeviceMac::SpeakerVolumeStepSize(uint16_t& stepSize) const -{ - - uint16_t delta(0); +int32_t AudioDeviceMac::SpeakerVolumeStepSize(uint16_t& stepSize) const { + uint16_t delta(0); - if (_mixerManager.SpeakerVolumeStepSize(delta) == -1) - { - return -1; - } + if (_mixerManager.SpeakerVolumeStepSize(delta) == -1) { + return -1; + } - stepSize = delta; - return 0; + stepSize = delta; + return 0; } -int32_t AudioDeviceMac::SpeakerMuteIsAvailable(bool& available) -{ - - bool isAvailable(false); - bool wasInitialized = _mixerManager.SpeakerIsInitialized(); +int32_t AudioDeviceMac::SpeakerMuteIsAvailable(bool& available) { + bool isAvailable(false); + bool wasInitialized = _mixerManager.SpeakerIsInitialized(); - // Make an attempt to open up the - // output mixer corresponding to the currently selected output device. - // - if (!wasInitialized && InitSpeaker() == -1) - { - // If we end up here it means that the selected speaker has no volume - // control, hence it is safe to state that there is no mute control - // already at this stage. - available = false; - return 0; - } + // Make an attempt to open up the + // output mixer corresponding to the currently selected output device. + // + if (!wasInitialized && InitSpeaker() == -1) { + // If we end up here it means that the selected speaker has no volume + // control, hence it is safe to state that there is no mute control + // already at this stage. + available = false; + return 0; + } - // Check if the selected speaker has a mute control - // - _mixerManager.SpeakerMuteIsAvailable(isAvailable); + // Check if the selected speaker has a mute control + // + _mixerManager.SpeakerMuteIsAvailable(isAvailable); - available = isAvailable; + available = isAvailable; - // Close the initialized output mixer - // - if (!wasInitialized) - { - _mixerManager.CloseSpeaker(); - } + // Close the initialized output mixer + // + if (!wasInitialized) { + _mixerManager.CloseSpeaker(); + } - return 0; + return 0; } -int32_t AudioDeviceMac::SetSpeakerMute(bool enable) -{ - return (_mixerManager.SetSpeakerMute(enable)); +int32_t AudioDeviceMac::SetSpeakerMute(bool enable) { + return (_mixerManager.SetSpeakerMute(enable)); } -int32_t AudioDeviceMac::SpeakerMute(bool& enabled) const -{ +int32_t AudioDeviceMac::SpeakerMute(bool& enabled) const { + bool muted(0); - bool muted(0); - - if (_mixerManager.SpeakerMute(muted) == -1) - { - return -1; - } + if (_mixerManager.SpeakerMute(muted) == -1) { + return -1; + } - enabled = muted; - return 0; + enabled = muted; + return 0; } -int32_t AudioDeviceMac::MicrophoneMuteIsAvailable(bool& available) -{ +int32_t AudioDeviceMac::MicrophoneMuteIsAvailable(bool& available) { + bool isAvailable(false); + bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); - bool isAvailable(false); - bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); - - // Make an attempt to open up the - // input mixer corresponding to the currently selected input device. - // - if (!wasInitialized && InitMicrophone() == -1) - { - // If we end up here it means that the selected microphone has no volume - // control, hence it is safe to state that there is no boost control - // already at this stage. - available = false; - return 0; - } + // Make an attempt to open up the + // input mixer corresponding to the currently selected input device. + // + if (!wasInitialized && InitMicrophone() == -1) { + // If we end up here it means that the selected microphone has no volume + // control, hence it is safe to state that there is no boost control + // already at this stage. + available = false; + return 0; + } - // Check if the selected microphone has a mute control - // - _mixerManager.MicrophoneMuteIsAvailable(isAvailable); - available = isAvailable; + // Check if the selected microphone has a mute control + // + _mixerManager.MicrophoneMuteIsAvailable(isAvailable); + available = isAvailable; - // Close the initialized input mixer - // - if (!wasInitialized) - { - _mixerManager.CloseMicrophone(); - } + // Close the initialized input mixer + // + if (!wasInitialized) { + _mixerManager.CloseMicrophone(); + } - return 0; + return 0; } -int32_t AudioDeviceMac::SetMicrophoneMute(bool enable) -{ - return (_mixerManager.SetMicrophoneMute(enable)); +int32_t AudioDeviceMac::SetMicrophoneMute(bool enable) { + return (_mixerManager.SetMicrophoneMute(enable)); } -int32_t AudioDeviceMac::MicrophoneMute(bool& enabled) const -{ +int32_t AudioDeviceMac::MicrophoneMute(bool& enabled) const { + bool muted(0); - bool muted(0); - - if (_mixerManager.MicrophoneMute(muted) == -1) - { - return -1; - } + if (_mixerManager.MicrophoneMute(muted) == -1) { + return -1; + } - enabled = muted; - return 0; + enabled = muted; + return 0; } -int32_t AudioDeviceMac::MicrophoneBoostIsAvailable(bool& available) -{ - - bool isAvailable(false); - bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); +int32_t AudioDeviceMac::MicrophoneBoostIsAvailable(bool& available) { + bool isAvailable(false); + bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); - // Enumerate all avaliable microphone and make an attempt to open up the - // input mixer corresponding to the currently selected input device. - // - if (!wasInitialized && InitMicrophone() == -1) - { - // If we end up here it means that the selected microphone has no volume - // control, hence it is safe to state that there is no boost control - // already at this stage. - available = false; - return 0; - } + // Enumerate all avaliable microphone and make an attempt to open up the + // input mixer corresponding to the currently selected input device. + // + if (!wasInitialized && InitMicrophone() == -1) { + // If we end up here it means that the selected microphone has no volume + // control, hence it is safe to state that there is no boost control + // already at this stage. + available = false; + return 0; + } - // Check if the selected microphone has a boost control - // - _mixerManager.MicrophoneBoostIsAvailable(isAvailable); - available = isAvailable; + // Check if the selected microphone has a boost control + // + _mixerManager.MicrophoneBoostIsAvailable(isAvailable); + available = isAvailable; - // Close the initialized input mixer - // - if (!wasInitialized) - { - _mixerManager.CloseMicrophone(); - } + // Close the initialized input mixer + // + if (!wasInitialized) { + _mixerManager.CloseMicrophone(); + } - return 0; + return 0; } -int32_t AudioDeviceMac::SetMicrophoneBoost(bool enable) -{ - - return (_mixerManager.SetMicrophoneBoost(enable)); +int32_t AudioDeviceMac::SetMicrophoneBoost(bool enable) { + return (_mixerManager.SetMicrophoneBoost(enable)); } -int32_t AudioDeviceMac::MicrophoneBoost(bool& enabled) const -{ - - bool onOff(0); +int32_t AudioDeviceMac::MicrophoneBoost(bool& enabled) const { + bool onOff(0); - if (_mixerManager.MicrophoneBoost(onOff) == -1) - { - return -1; - } + if (_mixerManager.MicrophoneBoost(onOff) == -1) { + return -1; + } - enabled = onOff; - return 0; + enabled = onOff; + return 0; } -int32_t AudioDeviceMac::StereoRecordingIsAvailable(bool& available) -{ - - bool isAvailable(false); - bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); - - if (!wasInitialized && InitMicrophone() == -1) - { - // Cannot open the specified device - available = false; - return 0; - } - - // Check if the selected microphone can record stereo - // - _mixerManager.StereoRecordingIsAvailable(isAvailable); - available = isAvailable; - - // Close the initialized input mixer - // - if (!wasInitialized) - { - _mixerManager.CloseMicrophone(); - } +int32_t AudioDeviceMac::StereoRecordingIsAvailable(bool& available) { + bool isAvailable(false); + bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); + if (!wasInitialized && InitMicrophone() == -1) { + // Cannot open the specified device + available = false; return 0; -} + } -int32_t AudioDeviceMac::SetStereoRecording(bool enable) -{ + // Check if the selected microphone can record stereo + // + _mixerManager.StereoRecordingIsAvailable(isAvailable); + available = isAvailable; - if (enable) - _recChannels = 2; - else - _recChannels = 1; + // Close the initialized input mixer + // + if (!wasInitialized) { + _mixerManager.CloseMicrophone(); + } - return 0; + return 0; } -int32_t AudioDeviceMac::StereoRecording(bool& enabled) const -{ +int32_t AudioDeviceMac::SetStereoRecording(bool enable) { + if (enable) + _recChannels = 2; + else + _recChannels = 1; - if (_recChannels == 2) - enabled = true; - else - enabled = false; - - return 0; + return 0; } -int32_t AudioDeviceMac::StereoPlayoutIsAvailable(bool& available) -{ - - bool isAvailable(false); - bool wasInitialized = _mixerManager.SpeakerIsInitialized(); +int32_t AudioDeviceMac::StereoRecording(bool& enabled) const { + if (_recChannels == 2) + enabled = true; + else + enabled = false; - if (!wasInitialized && InitSpeaker() == -1) - { - // Cannot open the specified device - available = false; - return 0; - } - - // Check if the selected microphone can record stereo - // - _mixerManager.StereoPlayoutIsAvailable(isAvailable); - available = isAvailable; + return 0; +} - // Close the initialized input mixer - // - if (!wasInitialized) - { - _mixerManager.CloseSpeaker(); - } +int32_t AudioDeviceMac::StereoPlayoutIsAvailable(bool& available) { + bool isAvailable(false); + bool wasInitialized = _mixerManager.SpeakerIsInitialized(); + if (!wasInitialized && InitSpeaker() == -1) { + // Cannot open the specified device + available = false; return 0; -} + } -int32_t AudioDeviceMac::SetStereoPlayout(bool enable) -{ + // Check if the selected microphone can record stereo + // + _mixerManager.StereoPlayoutIsAvailable(isAvailable); + available = isAvailable; - if (enable) - _playChannels = 2; - else - _playChannels = 1; + // Close the initialized input mixer + // + if (!wasInitialized) { + _mixerManager.CloseSpeaker(); + } - return 0; + return 0; } -int32_t AudioDeviceMac::StereoPlayout(bool& enabled) const -{ - - if (_playChannels == 2) - enabled = true; - else - enabled = false; +int32_t AudioDeviceMac::SetStereoPlayout(bool enable) { + if (enable) + _playChannels = 2; + else + _playChannels = 1; - return 0; + return 0; } -int32_t AudioDeviceMac::SetAGC(bool enable) -{ - - _AGC = enable; +int32_t AudioDeviceMac::StereoPlayout(bool& enabled) const { + if (_playChannels == 2) + enabled = true; + else + enabled = false; - return 0; + return 0; } -bool AudioDeviceMac::AGC() const -{ +int32_t AudioDeviceMac::SetAGC(bool enable) { + _AGC = enable; - return _AGC; + return 0; } -int32_t AudioDeviceMac::MicrophoneVolumeIsAvailable(bool& available) -{ +bool AudioDeviceMac::AGC() const { + return _AGC; +} - bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); +int32_t AudioDeviceMac::MicrophoneVolumeIsAvailable(bool& available) { + bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); - // Make an attempt to open up the - // input mixer corresponding to the currently selected output device. - // - if (!wasInitialized && InitMicrophone() == -1) - { - // If we end up here it means that the selected microphone has no volume - // control. - available = false; - return 0; - } + // Make an attempt to open up the + // input mixer corresponding to the currently selected output device. + // + if (!wasInitialized && InitMicrophone() == -1) { + // If we end up here it means that the selected microphone has no volume + // control. + available = false; + return 0; + } - // Given that InitMicrophone was successful, we know that a volume control - // exists - // - available = true; + // Given that InitMicrophone was successful, we know that a volume control + // exists + // + available = true; - // Close the initialized input mixer - // - if (!wasInitialized) - { - _mixerManager.CloseMicrophone(); - } + // Close the initialized input mixer + // + if (!wasInitialized) { + _mixerManager.CloseMicrophone(); + } - return 0; + return 0; } -int32_t AudioDeviceMac::SetMicrophoneVolume(uint32_t volume) -{ - - return (_mixerManager.SetMicrophoneVolume(volume)); +int32_t AudioDeviceMac::SetMicrophoneVolume(uint32_t volume) { + return (_mixerManager.SetMicrophoneVolume(volume)); } -int32_t AudioDeviceMac::MicrophoneVolume(uint32_t& volume) const -{ +int32_t AudioDeviceMac::MicrophoneVolume(uint32_t& volume) const { + uint32_t level(0); - uint32_t level(0); - - if (_mixerManager.MicrophoneVolume(level) == -1) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " failed to retrive current microphone level"); - return -1; - } + if (_mixerManager.MicrophoneVolume(level) == -1) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " failed to retrive current microphone level"); + return -1; + } - volume = level; - return 0; + volume = level; + return 0; } -int32_t -AudioDeviceMac::MaxMicrophoneVolume(uint32_t& maxVolume) const -{ - - uint32_t maxVol(0); +int32_t AudioDeviceMac::MaxMicrophoneVolume(uint32_t& maxVolume) const { + uint32_t maxVol(0); - if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1) - { - return -1; - } + if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1) { + return -1; + } - maxVolume = maxVol; - return 0; + maxVolume = maxVol; + return 0; } -int32_t -AudioDeviceMac::MinMicrophoneVolume(uint32_t& minVolume) const -{ - - uint32_t minVol(0); +int32_t AudioDeviceMac::MinMicrophoneVolume(uint32_t& minVolume) const { + uint32_t minVol(0); - if (_mixerManager.MinMicrophoneVolume(minVol) == -1) - { - return -1; - } + if (_mixerManager.MinMicrophoneVolume(minVol) == -1) { + return -1; + } - minVolume = minVol; - return 0; + minVolume = minVol; + return 0; } -int32_t -AudioDeviceMac::MicrophoneVolumeStepSize(uint16_t& stepSize) const -{ - - uint16_t delta(0); +int32_t AudioDeviceMac::MicrophoneVolumeStepSize(uint16_t& stepSize) const { + uint16_t delta(0); - if (_mixerManager.MicrophoneVolumeStepSize(delta) == -1) - { - return -1; - } + if (_mixerManager.MicrophoneVolumeStepSize(delta) == -1) { + return -1; + } - stepSize = delta; - return 0; + stepSize = delta; + return 0; } -int16_t AudioDeviceMac::PlayoutDevices() -{ - - AudioDeviceID playDevices[MaxNumberDevices]; - return GetNumberDevices(kAudioDevicePropertyScopeOutput, playDevices, - MaxNumberDevices); +int16_t AudioDeviceMac::PlayoutDevices() { + AudioDeviceID playDevices[MaxNumberDevices]; + return GetNumberDevices(kAudioDevicePropertyScopeOutput, playDevices, + MaxNumberDevices); } -int32_t AudioDeviceMac::SetPlayoutDevice(uint16_t index) -{ - CriticalSectionScoped lock(&_critSect); +int32_t AudioDeviceMac::SetPlayoutDevice(uint16_t index) { + CriticalSectionScoped lock(&_critSect); - if (_playIsInitialized) - { - return -1; - } + if (_playIsInitialized) { + return -1; + } - AudioDeviceID playDevices[MaxNumberDevices]; - uint32_t nDevices = GetNumberDevices(kAudioDevicePropertyScopeOutput, - playDevices, MaxNumberDevices); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " number of availiable waveform-audio output devices is %u", - nDevices); - - if (index > (nDevices - 1)) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " device index is out of range [0,%u]", (nDevices - 1)); - return -1; - } + AudioDeviceID playDevices[MaxNumberDevices]; + uint32_t nDevices = GetNumberDevices(kAudioDevicePropertyScopeOutput, + playDevices, MaxNumberDevices); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " number of availiable waveform-audio output devices is %u", + nDevices); - _outputDeviceIndex = index; - _outputDeviceIsSpecified = true; + if (index > (nDevices - 1)) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " device index is out of range [0,%u]", (nDevices - 1)); + return -1; + } - return 0; + _outputDeviceIndex = index; + _outputDeviceIsSpecified = true; + + return 0; } int32_t AudioDeviceMac::SetPlayoutDevice( - AudioDeviceModule::WindowsDeviceType /*device*/) -{ - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "WindowsDeviceType not supported"); - return -1; + AudioDeviceModule::WindowsDeviceType /*device*/) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "WindowsDeviceType not supported"); + return -1; } -int32_t AudioDeviceMac::PlayoutDeviceName( - uint16_t index, - char name[kAdmMaxDeviceNameSize], - char guid[kAdmMaxGuidSize]) -{ +int32_t AudioDeviceMac::PlayoutDeviceName(uint16_t index, + char name[kAdmMaxDeviceNameSize], + char guid[kAdmMaxGuidSize]) { + const uint16_t nDevices(PlayoutDevices()); - const uint16_t nDevices(PlayoutDevices()); - - if ((index > (nDevices - 1)) || (name == NULL)) - { - return -1; - } + if ((index > (nDevices - 1)) || (name == NULL)) { + return -1; + } - memset(name, 0, kAdmMaxDeviceNameSize); + memset(name, 0, kAdmMaxDeviceNameSize); - if (guid != NULL) - { - memset(guid, 0, kAdmMaxGuidSize); - } + if (guid != NULL) { + memset(guid, 0, kAdmMaxGuidSize); + } - return GetDeviceName(kAudioDevicePropertyScopeOutput, index, name); + return GetDeviceName(kAudioDevicePropertyScopeOutput, index, name); } -int32_t AudioDeviceMac::RecordingDeviceName( - uint16_t index, - char name[kAdmMaxDeviceNameSize], - char guid[kAdmMaxGuidSize]) -{ - - const uint16_t nDevices(RecordingDevices()); +int32_t AudioDeviceMac::RecordingDeviceName(uint16_t index, + char name[kAdmMaxDeviceNameSize], + char guid[kAdmMaxGuidSize]) { + const uint16_t nDevices(RecordingDevices()); - if ((index > (nDevices - 1)) || (name == NULL)) - { - return -1; - } + if ((index > (nDevices - 1)) || (name == NULL)) { + return -1; + } - memset(name, 0, kAdmMaxDeviceNameSize); + memset(name, 0, kAdmMaxDeviceNameSize); - if (guid != NULL) - { - memset(guid, 0, kAdmMaxGuidSize); - } + if (guid != NULL) { + memset(guid, 0, kAdmMaxGuidSize); + } - return GetDeviceName(kAudioDevicePropertyScopeInput, index, name); + return GetDeviceName(kAudioDevicePropertyScopeInput, index, name); } -int16_t AudioDeviceMac::RecordingDevices() -{ - - AudioDeviceID recDevices[MaxNumberDevices]; - return GetNumberDevices(kAudioDevicePropertyScopeInput, recDevices, - MaxNumberDevices); +int16_t AudioDeviceMac::RecordingDevices() { + AudioDeviceID recDevices[MaxNumberDevices]; + return GetNumberDevices(kAudioDevicePropertyScopeInput, recDevices, + MaxNumberDevices); } -int32_t AudioDeviceMac::SetRecordingDevice(uint16_t index) -{ +int32_t AudioDeviceMac::SetRecordingDevice(uint16_t index) { + if (_recIsInitialized) { + return -1; + } - if (_recIsInitialized) - { - return -1; - } + AudioDeviceID recDevices[MaxNumberDevices]; + uint32_t nDevices = GetNumberDevices(kAudioDevicePropertyScopeInput, + recDevices, MaxNumberDevices); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " number of availiable waveform-audio input devices is %u", + nDevices); - AudioDeviceID recDevices[MaxNumberDevices]; - uint32_t nDevices = GetNumberDevices(kAudioDevicePropertyScopeInput, - recDevices, MaxNumberDevices); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " number of availiable waveform-audio input devices is %u", - nDevices); - - if (index > (nDevices - 1)) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " device index is out of range [0,%u]", (nDevices - 1)); - return -1; - } + if (index > (nDevices - 1)) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " device index is out of range [0,%u]", (nDevices - 1)); + return -1; + } - _inputDeviceIndex = index; - _inputDeviceIsSpecified = true; + _inputDeviceIndex = index; + _inputDeviceIsSpecified = true; - return 0; + return 0; } - -int32_t -AudioDeviceMac::SetRecordingDevice(AudioDeviceModule::WindowsDeviceType /*device*/) -{ - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "WindowsDeviceType not supported"); - return -1; +int32_t AudioDeviceMac::SetRecordingDevice( + AudioDeviceModule::WindowsDeviceType /*device*/) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "WindowsDeviceType not supported"); + return -1; } -int32_t AudioDeviceMac::PlayoutIsAvailable(bool& available) -{ - - available = true; +int32_t AudioDeviceMac::PlayoutIsAvailable(bool& available) { + available = true; - // Try to initialize the playout side - if (InitPlayout() == -1) - { - available = false; - } + // Try to initialize the playout side + if (InitPlayout() == -1) { + available = false; + } - // We destroy the IOProc created by InitPlayout() in implDeviceIOProc(). - // We must actually start playout here in order to have the IOProc - // deleted by calling StopPlayout(). - if (StartPlayout() == -1) - { - available = false; - } + // We destroy the IOProc created by InitPlayout() in implDeviceIOProc(). + // We must actually start playout here in order to have the IOProc + // deleted by calling StopPlayout(). + if (StartPlayout() == -1) { + available = false; + } - // Cancel effect of initialization - if (StopPlayout() == -1) - { - available = false; - } + // Cancel effect of initialization + if (StopPlayout() == -1) { + available = false; + } - return 0; + return 0; } -int32_t AudioDeviceMac::RecordingIsAvailable(bool& available) -{ - - available = true; +int32_t AudioDeviceMac::RecordingIsAvailable(bool& available) { + available = true; - // Try to initialize the recording side - if (InitRecording() == -1) - { - available = false; - } + // Try to initialize the recording side + if (InitRecording() == -1) { + available = false; + } - // We destroy the IOProc created by InitRecording() in implInDeviceIOProc(). - // We must actually start recording here in order to have the IOProc - // deleted by calling StopRecording(). - if (StartRecording() == -1) - { - available = false; - } + // We destroy the IOProc created by InitRecording() in implInDeviceIOProc(). + // We must actually start recording here in order to have the IOProc + // deleted by calling StopRecording(). + if (StartRecording() == -1) { + available = false; + } - // Cancel effect of initialization - if (StopRecording() == -1) - { - available = false; - } + // Cancel effect of initialization + if (StopRecording() == -1) { + available = false; + } - return 0; + return 0; } -int32_t AudioDeviceMac::InitPlayout() -{ - CriticalSectionScoped lock(&_critSect); +int32_t AudioDeviceMac::InitPlayout() { + CriticalSectionScoped lock(&_critSect); - if (_playing) - { - return -1; - } + if (_playing) { + return -1; + } - if (!_outputDeviceIsSpecified) - { - return -1; - } + if (!_outputDeviceIsSpecified) { + return -1; + } - if (_playIsInitialized) - { - return 0; - } + if (_playIsInitialized) { + return 0; + } - // Initialize the speaker (devices might have been added or removed) - if (InitSpeaker() == -1) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " InitSpeaker() failed"); - } + // Initialize the speaker (devices might have been added or removed) + if (InitSpeaker() == -1) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " InitSpeaker() failed"); + } - if (!MicrophoneIsInitialized()) - { - // Make this call to check if we are using - // one or two devices (_twoDevices) - bool available = false; - if (MicrophoneIsAvailable(available) == -1) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " MicrophoneIsAvailable() failed"); - } + if (!MicrophoneIsInitialized()) { + // Make this call to check if we are using + // one or two devices (_twoDevices) + bool available = false; + if (MicrophoneIsAvailable(available) == -1) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " MicrophoneIsAvailable() failed"); } + } - PaUtil_FlushRingBuffer(_paRenderBuffer); - - OSStatus err = noErr; - UInt32 size = 0; - _renderDelayOffsetSamples = 0; - _renderDelayUs = 0; - _renderLatencyUs = 0; - _renderDeviceIsAlive = 1; - _doStop = false; + PaUtil_FlushRingBuffer(_paRenderBuffer); + + OSStatus err = noErr; + UInt32 size = 0; + _renderDelayOffsetSamples = 0; + _renderDelayUs = 0; + _renderLatencyUs = 0; + _renderDeviceIsAlive = 1; + _doStop = false; + + // The internal microphone of a MacBook Pro is located under the left speaker + // grille. When the internal speakers are in use, we want to fully stereo + // pan to the right. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyDataSource, kAudioDevicePropertyScopeOutput, 0}; + if (_macBookPro) { + _macBookProPanRight = false; + Boolean hasProperty = + AudioObjectHasProperty(_outputDeviceID, &propertyAddress); + if (hasProperty) { + UInt32 dataSource = 0; + size = sizeof(dataSource); + WEBRTC_CA_LOG_WARN(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &dataSource)); + + if (dataSource == 'ispk') { + _macBookProPanRight = true; + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "MacBook Pro using internal speakers; stereo" + " panning right"); + } else { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "MacBook Pro not using internal speakers"); + } - // The internal microphone of a MacBook Pro is located under the left speaker - // grille. When the internal speakers are in use, we want to fully stereo - // pan to the right. - AudioObjectPropertyAddress - propertyAddress = { kAudioDevicePropertyDataSource, - kAudioDevicePropertyScopeOutput, 0 }; - if (_macBookPro) - { - _macBookProPanRight = false; - Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID, - &propertyAddress); - if (hasProperty) - { - UInt32 dataSource = 0; - size = sizeof(dataSource); - WEBRTC_CA_LOG_WARN(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, &size, &dataSource)); - - if (dataSource == 'ispk') - { - _macBookProPanRight = true; - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, - _id, - "MacBook Pro using internal speakers; stereo" - " panning right"); - } else - { - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, - _id, "MacBook Pro not using internal speakers"); - } - - // Add a listener to determine if the status changes. - WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener(_outputDeviceID, - &propertyAddress, &objectListenerProc, this)); - } + // Add a listener to determine if the status changes. + WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener( + _outputDeviceID, &propertyAddress, &objectListenerProc, this)); } + } - // Get current stream description - propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; - memset(&_outStreamFormat, 0, sizeof(_outStreamFormat)); - size = sizeof(_outStreamFormat); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, 0, NULL, &size, &_outStreamFormat)); - - if (_outStreamFormat.mFormatID != kAudioFormatLinearPCM) - { - logCAMsg(kTraceError, kTraceAudioDevice, _id, - "Unacceptable output stream format -> mFormatID", - (const char *) &_outStreamFormat.mFormatID); - return -1; - } + // Get current stream description + propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; + memset(&_outStreamFormat, 0, sizeof(_outStreamFormat)); + size = sizeof(_outStreamFormat); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &_outStreamFormat)); + + if (_outStreamFormat.mFormatID != kAudioFormatLinearPCM) { + logCAMsg(kTraceError, kTraceAudioDevice, _id, + "Unacceptable output stream format -> mFormatID", + (const char*)&_outStreamFormat.mFormatID); + return -1; + } - if (_outStreamFormat.mChannelsPerFrame > N_DEVICE_CHANNELS) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "Too many channels on output device (mChannelsPerFrame = %d)", - _outStreamFormat.mChannelsPerFrame); - return -1; - } + if (_outStreamFormat.mChannelsPerFrame > N_DEVICE_CHANNELS) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "Too many channels on output device (mChannelsPerFrame = %d)", + _outStreamFormat.mChannelsPerFrame); + return -1; + } - if (_outStreamFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "Non-interleaved audio data is not supported.", - "AudioHardware streams should not have this format."); - return -1; - } + if (_outStreamFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "Non-interleaved audio data is not supported.", + "AudioHardware streams should not have this format."); + return -1; + } + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Ouput stream format:"); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "mSampleRate = %f, mChannelsPerFrame = %u", + _outStreamFormat.mSampleRate, + _outStreamFormat.mChannelsPerFrame); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "mBytesPerPacket = %u, mFramesPerPacket = %u", + _outStreamFormat.mBytesPerPacket, + _outStreamFormat.mFramesPerPacket); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "mBytesPerFrame = %u, mBitsPerChannel = %u", + _outStreamFormat.mBytesPerFrame, + _outStreamFormat.mBitsPerChannel); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "mFormatFlags = %u", + _outStreamFormat.mFormatFlags); + logCAMsg(kTraceInfo, kTraceAudioDevice, _id, "mFormatID", + (const char*)&_outStreamFormat.mFormatID); + + // Our preferred format to work with. + if (_outStreamFormat.mChannelsPerFrame < 2) { + // Disable stereo playout when we only have one channel on the device. + _playChannels = 1; WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "Ouput stream format:"); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "mSampleRate = %f, mChannelsPerFrame = %u", - _outStreamFormat.mSampleRate, - _outStreamFormat.mChannelsPerFrame); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "mBytesPerPacket = %u, mFramesPerPacket = %u", - _outStreamFormat.mBytesPerPacket, - _outStreamFormat.mFramesPerPacket); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "mBytesPerFrame = %u, mBitsPerChannel = %u", - _outStreamFormat.mBytesPerFrame, - _outStreamFormat.mBitsPerChannel); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "mFormatFlags = %u", - _outStreamFormat.mFormatFlags); - logCAMsg(kTraceInfo, kTraceAudioDevice, _id, "mFormatID", - (const char *) &_outStreamFormat.mFormatID); - - // Our preferred format to work with. - if (_outStreamFormat.mChannelsPerFrame < 2) - { - // Disable stereo playout when we only have one channel on the device. - _playChannels = 1; - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "Stereo playout unavailable on this device"); - } - WEBRTC_CA_RETURN_ON_ERR(SetDesiredPlayoutFormat()); + "Stereo playout unavailable on this device"); + } + WEBRTC_CA_RETURN_ON_ERR(SetDesiredPlayoutFormat()); - // Listen for format changes. - propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; - WEBRTC_CA_RETURN_ON_ERR(AudioObjectAddPropertyListener(_outputDeviceID, - &propertyAddress, - &objectListenerProc, - this)); - - // Listen for processor overloads. - propertyAddress.mSelector = kAudioDeviceProcessorOverload; - WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener(_outputDeviceID, - &propertyAddress, - &objectListenerProc, - this)); - - if (_twoDevices || !_recIsInitialized) - { - WEBRTC_CA_RETURN_ON_ERR(AudioDeviceCreateIOProcID(_outputDeviceID, - deviceIOProc, - this, - &_deviceIOProcID)); - } + // Listen for format changes. + propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; + WEBRTC_CA_RETURN_ON_ERR(AudioObjectAddPropertyListener( + _outputDeviceID, &propertyAddress, &objectListenerProc, this)); - _playIsInitialized = true; + // Listen for processor overloads. + propertyAddress.mSelector = kAudioDeviceProcessorOverload; + WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener( + _outputDeviceID, &propertyAddress, &objectListenerProc, this)); - return 0; + if (_twoDevices || !_recIsInitialized) { + WEBRTC_CA_RETURN_ON_ERR(AudioDeviceCreateIOProcID( + _outputDeviceID, deviceIOProc, this, &_deviceIOProcID)); + } + + _playIsInitialized = true; + + return 0; } -int32_t AudioDeviceMac::InitRecording() -{ +int32_t AudioDeviceMac::InitRecording() { + CriticalSectionScoped lock(&_critSect); - CriticalSectionScoped lock(&_critSect); + if (_recording) { + return -1; + } - if (_recording) - { - return -1; - } + if (!_inputDeviceIsSpecified) { + return -1; + } - if (!_inputDeviceIsSpecified) - { - return -1; - } + if (_recIsInitialized) { + return 0; + } - if (_recIsInitialized) - { - return 0; - } + // Initialize the microphone (devices might have been added or removed) + if (InitMicrophone() == -1) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " InitMicrophone() failed"); + } - // Initialize the microphone (devices might have been added or removed) - if (InitMicrophone() == -1) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " InitMicrophone() failed"); + if (!SpeakerIsInitialized()) { + // Make this call to check if we are using + // one or two devices (_twoDevices) + bool available = false; + if (SpeakerIsAvailable(available) == -1) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " SpeakerIsAvailable() failed"); } + } - if (!SpeakerIsInitialized()) - { - // Make this call to check if we are using - // one or two devices (_twoDevices) - bool available = false; - if (SpeakerIsAvailable(available) == -1) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " SpeakerIsAvailable() failed"); - } - } + OSStatus err = noErr; + UInt32 size = 0; - OSStatus err = noErr; - UInt32 size = 0; - - PaUtil_FlushRingBuffer(_paCaptureBuffer); - - _captureDelayUs = 0; - _captureLatencyUs = 0; - _captureDeviceIsAlive = 1; - _doStopRec = false; - - // Get current stream description - AudioObjectPropertyAddress - propertyAddress = { kAudioDevicePropertyStreamFormat, - kAudioDevicePropertyScopeInput, 0 }; - memset(&_inStreamFormat, 0, sizeof(_inStreamFormat)); - size = sizeof(_inStreamFormat); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &_inStreamFormat)); - - if (_inStreamFormat.mFormatID != kAudioFormatLinearPCM) - { - logCAMsg(kTraceError, kTraceAudioDevice, _id, - "Unacceptable input stream format -> mFormatID", - (const char *) &_inStreamFormat.mFormatID); - return -1; - } + PaUtil_FlushRingBuffer(_paCaptureBuffer); - if (_inStreamFormat.mChannelsPerFrame > N_DEVICE_CHANNELS) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "Too many channels on input device (mChannelsPerFrame = %d)", - _inStreamFormat.mChannelsPerFrame); - return -1; - } + _captureDelayUs = 0; + _captureLatencyUs = 0; + _captureDeviceIsAlive = 1; + _doStopRec = false; - const int io_block_size_samples = _inStreamFormat.mChannelsPerFrame * - _inStreamFormat.mSampleRate / 100 * N_BLOCKS_IO; - if (io_block_size_samples > _captureBufSizeSamples) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "Input IO block size (%d) is larger than ring buffer (%u)", - io_block_size_samples, _captureBufSizeSamples); - return -1; - } + // Get current stream description + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput, 0}; + memset(&_inStreamFormat, 0, sizeof(_inStreamFormat)); + size = sizeof(_inStreamFormat); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &_inStreamFormat)); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " Input stream format:"); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " mSampleRate = %f, mChannelsPerFrame = %u", - _inStreamFormat.mSampleRate, _inStreamFormat.mChannelsPerFrame); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " mBytesPerPacket = %u, mFramesPerPacket = %u", - _inStreamFormat.mBytesPerPacket, - _inStreamFormat.mFramesPerPacket); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " mBytesPerFrame = %u, mBitsPerChannel = %u", - _inStreamFormat.mBytesPerFrame, - _inStreamFormat.mBitsPerChannel); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " mFormatFlags = %u", - _inStreamFormat.mFormatFlags); - logCAMsg(kTraceInfo, kTraceAudioDevice, _id, "mFormatID", - (const char *) &_inStreamFormat.mFormatID); + if (_inStreamFormat.mFormatID != kAudioFormatLinearPCM) { + logCAMsg(kTraceError, kTraceAudioDevice, _id, + "Unacceptable input stream format -> mFormatID", + (const char*)&_inStreamFormat.mFormatID); + return -1; + } - // Our preferred format to work with - if (_inStreamFormat.mChannelsPerFrame >= 2 && (_recChannels == 2)) - { - _inDesiredFormat.mChannelsPerFrame = 2; - } else - { - // Disable stereo recording when we only have one channel on the device. - _inDesiredFormat.mChannelsPerFrame = 1; - _recChannels = 1; - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "Stereo recording unavailable on this device"); - } + if (_inStreamFormat.mChannelsPerFrame > N_DEVICE_CHANNELS) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "Too many channels on input device (mChannelsPerFrame = %d)", + _inStreamFormat.mChannelsPerFrame); + return -1; + } - if (_ptrAudioBuffer) - { - // Update audio buffer with the selected parameters - _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); - _ptrAudioBuffer->SetRecordingChannels((uint8_t) _recChannels); - } + const int io_block_size_samples = _inStreamFormat.mChannelsPerFrame * + _inStreamFormat.mSampleRate / 100 * + N_BLOCKS_IO; + if (io_block_size_samples > _captureBufSizeSamples) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "Input IO block size (%d) is larger than ring buffer (%u)", + io_block_size_samples, _captureBufSizeSamples); + return -1; + } + + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " Input stream format:"); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " mSampleRate = %f, mChannelsPerFrame = %u", + _inStreamFormat.mSampleRate, _inStreamFormat.mChannelsPerFrame); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " mBytesPerPacket = %u, mFramesPerPacket = %u", + _inStreamFormat.mBytesPerPacket, + _inStreamFormat.mFramesPerPacket); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " mBytesPerFrame = %u, mBitsPerChannel = %u", + _inStreamFormat.mBytesPerFrame, _inStreamFormat.mBitsPerChannel); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " mFormatFlags = %u", + _inStreamFormat.mFormatFlags); + logCAMsg(kTraceInfo, kTraceAudioDevice, _id, "mFormatID", + (const char*)&_inStreamFormat.mFormatID); + + // Our preferred format to work with + if (_inStreamFormat.mChannelsPerFrame >= 2 && (_recChannels == 2)) { + _inDesiredFormat.mChannelsPerFrame = 2; + } else { + // Disable stereo recording when we only have one channel on the device. + _inDesiredFormat.mChannelsPerFrame = 1; + _recChannels = 1; + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "Stereo recording unavailable on this device"); + } + + if (_ptrAudioBuffer) { + // Update audio buffer with the selected parameters + _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); + _ptrAudioBuffer->SetRecordingChannels((uint8_t)_recChannels); + } - _inDesiredFormat.mSampleRate = N_REC_SAMPLES_PER_SEC; - _inDesiredFormat.mBytesPerPacket = _inDesiredFormat.mChannelsPerFrame - * sizeof(SInt16); - _inDesiredFormat.mFramesPerPacket = 1; - _inDesiredFormat.mBytesPerFrame = _inDesiredFormat.mChannelsPerFrame - * sizeof(SInt16); - _inDesiredFormat.mBitsPerChannel = sizeof(SInt16) * 8; + _inDesiredFormat.mSampleRate = N_REC_SAMPLES_PER_SEC; + _inDesiredFormat.mBytesPerPacket = + _inDesiredFormat.mChannelsPerFrame * sizeof(SInt16); + _inDesiredFormat.mFramesPerPacket = 1; + _inDesiredFormat.mBytesPerFrame = + _inDesiredFormat.mChannelsPerFrame * sizeof(SInt16); + _inDesiredFormat.mBitsPerChannel = sizeof(SInt16) * 8; - _inDesiredFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger - | kLinearPCMFormatFlagIsPacked; + _inDesiredFormat.mFormatFlags = + kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; #ifdef WEBRTC_ARCH_BIG_ENDIAN - _inDesiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; + _inDesiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; #endif - _inDesiredFormat.mFormatID = kAudioFormatLinearPCM; - - WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew(&_inStreamFormat, &_inDesiredFormat, - &_captureConverter)); - - // First try to set buffer size to desired value (10 ms * N_BLOCKS_IO) - // TODO(xians): investigate this block. - UInt32 bufByteCount = (UInt32)((_inStreamFormat.mSampleRate / 1000.0) - * 10.0 * N_BLOCKS_IO * _inStreamFormat.mChannelsPerFrame - * sizeof(Float32)); - if (_inStreamFormat.mFramesPerPacket != 0) - { - if (bufByteCount % _inStreamFormat.mFramesPerPacket != 0) - { - bufByteCount = ((UInt32)(bufByteCount - / _inStreamFormat.mFramesPerPacket) + 1) - * _inStreamFormat.mFramesPerPacket; - } + _inDesiredFormat.mFormatID = kAudioFormatLinearPCM; + + WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew(&_inStreamFormat, &_inDesiredFormat, + &_captureConverter)); + + // First try to set buffer size to desired value (10 ms * N_BLOCKS_IO) + // TODO(xians): investigate this block. + UInt32 bufByteCount = + (UInt32)((_inStreamFormat.mSampleRate / 1000.0) * 10.0 * N_BLOCKS_IO * + _inStreamFormat.mChannelsPerFrame * sizeof(Float32)); + if (_inStreamFormat.mFramesPerPacket != 0) { + if (bufByteCount % _inStreamFormat.mFramesPerPacket != 0) { + bufByteCount = + ((UInt32)(bufByteCount / _inStreamFormat.mFramesPerPacket) + 1) * + _inStreamFormat.mFramesPerPacket; } + } - // Ensure the buffer size is within the acceptable range provided by the device. - propertyAddress.mSelector = kAudioDevicePropertyBufferSizeRange; - AudioValueRange range; - size = sizeof(range); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &range)); - if (range.mMinimum > bufByteCount) - { - bufByteCount = range.mMinimum; - } else if (range.mMaximum < bufByteCount) - { - bufByteCount = range.mMaximum; - } + // Ensure the buffer size is within the acceptable range provided by the + // device. + propertyAddress.mSelector = kAudioDevicePropertyBufferSizeRange; + AudioValueRange range; + size = sizeof(range); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &range)); + if (range.mMinimum > bufByteCount) { + bufByteCount = range.mMinimum; + } else if (range.mMaximum < bufByteCount) { + bufByteCount = range.mMaximum; + } - propertyAddress.mSelector = kAudioDevicePropertyBufferSize; - size = sizeof(bufByteCount); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, size, &bufByteCount)); - - // Get capture device latency - propertyAddress.mSelector = kAudioDevicePropertyLatency; - UInt32 latency = 0; - size = sizeof(UInt32); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &latency)); - _captureLatencyUs = (UInt32)((1.0e6 * latency) - / _inStreamFormat.mSampleRate); - - // Get capture stream latency - propertyAddress.mSelector = kAudioDevicePropertyStreams; - AudioStreamID stream = 0; - size = sizeof(AudioStreamID); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &stream)); - propertyAddress.mSelector = kAudioStreamPropertyLatency; - size = sizeof(UInt32); - latency = 0; - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, - &propertyAddress, 0, NULL, &size, &latency)); - _captureLatencyUs += (UInt32)((1.0e6 * latency) - / _inStreamFormat.mSampleRate); - - // Listen for format changes - // TODO(xians): should we be using kAudioDevicePropertyDeviceHasChanged? - propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; - WEBRTC_CA_RETURN_ON_ERR(AudioObjectAddPropertyListener(_inputDeviceID, - &propertyAddress, &objectListenerProc, this)); - - // Listen for processor overloads - propertyAddress.mSelector = kAudioDeviceProcessorOverload; - WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener(_inputDeviceID, - &propertyAddress, &objectListenerProc, this)); - - if (_twoDevices) - { - WEBRTC_CA_RETURN_ON_ERR(AudioDeviceCreateIOProcID(_inputDeviceID, - inDeviceIOProc, this, &_inDeviceIOProcID)); - } else if (!_playIsInitialized) - { - WEBRTC_CA_RETURN_ON_ERR(AudioDeviceCreateIOProcID(_inputDeviceID, - deviceIOProc, this, &_deviceIOProcID)); - } + propertyAddress.mSelector = kAudioDevicePropertyBufferSize; + size = sizeof(bufByteCount); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, size, &bufByteCount)); + + // Get capture device latency + propertyAddress.mSelector = kAudioDevicePropertyLatency; + UInt32 latency = 0; + size = sizeof(UInt32); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &latency)); + _captureLatencyUs = (UInt32)((1.0e6 * latency) / _inStreamFormat.mSampleRate); + + // Get capture stream latency + propertyAddress.mSelector = kAudioDevicePropertyStreams; + AudioStreamID stream = 0; + size = sizeof(AudioStreamID); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &stream)); + propertyAddress.mSelector = kAudioStreamPropertyLatency; + size = sizeof(UInt32); + latency = 0; + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _inputDeviceID, &propertyAddress, 0, NULL, &size, &latency)); + _captureLatencyUs += + (UInt32)((1.0e6 * latency) / _inStreamFormat.mSampleRate); + + // Listen for format changes + // TODO(xians): should we be using kAudioDevicePropertyDeviceHasChanged? + propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; + WEBRTC_CA_RETURN_ON_ERR(AudioObjectAddPropertyListener( + _inputDeviceID, &propertyAddress, &objectListenerProc, this)); + + // Listen for processor overloads + propertyAddress.mSelector = kAudioDeviceProcessorOverload; + WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener( + _inputDeviceID, &propertyAddress, &objectListenerProc, this)); + + if (_twoDevices) { + WEBRTC_CA_RETURN_ON_ERR(AudioDeviceCreateIOProcID( + _inputDeviceID, inDeviceIOProc, this, &_inDeviceIOProcID)); + } else if (!_playIsInitialized) { + WEBRTC_CA_RETURN_ON_ERR(AudioDeviceCreateIOProcID( + _inputDeviceID, deviceIOProc, this, &_deviceIOProcID)); + } - // Mark recording side as initialized - _recIsInitialized = true; + // Mark recording side as initialized + _recIsInitialized = true; - return 0; + return 0; } -int32_t AudioDeviceMac::StartRecording() -{ - - CriticalSectionScoped lock(&_critSect); +int32_t AudioDeviceMac::StartRecording() { + CriticalSectionScoped lock(&_critSect); - if (!_recIsInitialized) - { - return -1; - } - - if (_recording) - { - return 0; - } + if (!_recIsInitialized) { + return -1; + } - if (!_initialized) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " Recording worker thread has not been started"); - return -1; - } + if (_recording) { + return 0; + } - RTC_DCHECK(!capture_worker_thread_.get()); - capture_worker_thread_.reset( - new rtc::PlatformThread(RunCapture, this, "CaptureWorkerThread")); - RTC_DCHECK(capture_worker_thread_.get()); - capture_worker_thread_->Start(); - capture_worker_thread_->SetPriority(rtc::kRealtimePriority); + if (!_initialized) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " Recording worker thread has not been started"); + return -1; + } - OSStatus err = noErr; - if (_twoDevices) - { - WEBRTC_CA_RETURN_ON_ERR(AudioDeviceStart(_inputDeviceID, _inDeviceIOProcID)); - } else if (!_playing) - { - WEBRTC_CA_RETURN_ON_ERR(AudioDeviceStart(_inputDeviceID, _deviceIOProcID)); - } + RTC_DCHECK(!capture_worker_thread_.get()); + capture_worker_thread_.reset( + new rtc::PlatformThread(RunCapture, this, "CaptureWorkerThread")); + RTC_DCHECK(capture_worker_thread_.get()); + capture_worker_thread_->Start(); + capture_worker_thread_->SetPriority(rtc::kRealtimePriority); + + OSStatus err = noErr; + if (_twoDevices) { + WEBRTC_CA_RETURN_ON_ERR( + AudioDeviceStart(_inputDeviceID, _inDeviceIOProcID)); + } else if (!_playing) { + WEBRTC_CA_RETURN_ON_ERR(AudioDeviceStart(_inputDeviceID, _deviceIOProcID)); + } - _recording = true; + _recording = true; - return 0; + return 0; } -int32_t AudioDeviceMac::StopRecording() -{ - - CriticalSectionScoped lock(&_critSect); +int32_t AudioDeviceMac::StopRecording() { + CriticalSectionScoped lock(&_critSect); - if (!_recIsInitialized) - { - return 0; - } - - OSStatus err = noErr; + if (!_recIsInitialized) { + return 0; + } - // Stop device - int32_t captureDeviceIsAlive = AtomicGet32(&_captureDeviceIsAlive); - if (_twoDevices) - { - if (_recording && captureDeviceIsAlive == 1) - { - _recording = false; - _doStopRec = true; // Signal to io proc to stop audio device - _critSect.Leave(); // Cannot be under lock, risk of deadlock - if (kEventTimeout == _stopEventRec.Wait(2000)) - { - CriticalSectionScoped critScoped(&_critSect); - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Timed out stopping the capture IOProc. " - "We may have failed to detect a device removal."); - - WEBRTC_CA_LOG_WARN(AudioDeviceStop(_inputDeviceID, - _inDeviceIOProcID)); - WEBRTC_CA_LOG_WARN( - AudioDeviceDestroyIOProcID(_inputDeviceID, - _inDeviceIOProcID)); - } - _critSect.Enter(); - _doStopRec = false; - WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, - " Recording stopped"); - } - } - else - { - // We signal a stop for a shared device even when rendering has - // not yet ended. This is to ensure the IOProc will return early as - // intended (by checking |_recording|) before accessing - // resources we free below (e.g. the capture converter). - // - // In the case of a shared devcie, the IOProc will verify - // rendering has ended before stopping itself. - if (_recording && captureDeviceIsAlive == 1) - { - _recording = false; - _doStop = true; // Signal to io proc to stop audio device - _critSect.Leave(); // Cannot be under lock, risk of deadlock - if (kEventTimeout == _stopEvent.Wait(2000)) - { - CriticalSectionScoped critScoped(&_critSect); - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Timed out stopping the shared IOProc. " - "We may have failed to detect a device removal."); - - // We assume rendering on a shared device has stopped as well if - // the IOProc times out. - WEBRTC_CA_LOG_WARN(AudioDeviceStop(_outputDeviceID, - _deviceIOProcID)); - WEBRTC_CA_LOG_WARN(AudioDeviceDestroyIOProcID(_outputDeviceID, - _deviceIOProcID)); - } - _critSect.Enter(); - _doStop = false; - WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, - " Recording stopped (shared)"); - } + OSStatus err = noErr; + + // Stop device + int32_t captureDeviceIsAlive = AtomicGet32(&_captureDeviceIsAlive); + if (_twoDevices) { + if (_recording && captureDeviceIsAlive == 1) { + _recording = false; + _doStopRec = true; // Signal to io proc to stop audio device + _critSect.Leave(); // Cannot be under lock, risk of deadlock + if (kEventTimeout == _stopEventRec.Wait(2000)) { + CriticalSectionScoped critScoped(&_critSect); + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Timed out stopping the capture IOProc. " + "We may have failed to detect a device removal."); + + WEBRTC_CA_LOG_WARN(AudioDeviceStop(_inputDeviceID, _inDeviceIOProcID)); + WEBRTC_CA_LOG_WARN( + AudioDeviceDestroyIOProcID(_inputDeviceID, _inDeviceIOProcID)); + } + _critSect.Enter(); + _doStopRec = false; + WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, " Recording stopped"); + } + } else { + // We signal a stop for a shared device even when rendering has + // not yet ended. This is to ensure the IOProc will return early as + // intended (by checking |_recording|) before accessing + // resources we free below (e.g. the capture converter). + // + // In the case of a shared devcie, the IOProc will verify + // rendering has ended before stopping itself. + if (_recording && captureDeviceIsAlive == 1) { + _recording = false; + _doStop = true; // Signal to io proc to stop audio device + _critSect.Leave(); // Cannot be under lock, risk of deadlock + if (kEventTimeout == _stopEvent.Wait(2000)) { + CriticalSectionScoped critScoped(&_critSect); + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Timed out stopping the shared IOProc. " + "We may have failed to detect a device removal."); + + // We assume rendering on a shared device has stopped as well if + // the IOProc times out. + WEBRTC_CA_LOG_WARN(AudioDeviceStop(_outputDeviceID, _deviceIOProcID)); + WEBRTC_CA_LOG_WARN( + AudioDeviceDestroyIOProcID(_outputDeviceID, _deviceIOProcID)); + } + _critSect.Enter(); + _doStop = false; + WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, + " Recording stopped (shared)"); } + } - // Setting this signal will allow the worker thread to be stopped. - AtomicSet32(&_captureDeviceIsAlive, 0); + // Setting this signal will allow the worker thread to be stopped. + AtomicSet32(&_captureDeviceIsAlive, 0); - if (capture_worker_thread_.get()) { - _critSect.Leave(); - capture_worker_thread_->Stop(); - capture_worker_thread_.reset(); - _critSect.Enter(); - } + if (capture_worker_thread_.get()) { + _critSect.Leave(); + capture_worker_thread_->Stop(); + capture_worker_thread_.reset(); + _critSect.Enter(); + } - WEBRTC_CA_LOG_WARN(AudioConverterDispose(_captureConverter)); + WEBRTC_CA_LOG_WARN(AudioConverterDispose(_captureConverter)); - // Remove listeners. - AudioObjectPropertyAddress - propertyAddress = { kAudioDevicePropertyStreamFormat, - kAudioDevicePropertyScopeInput, 0 }; - WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_inputDeviceID, - &propertyAddress, &objectListenerProc, this)); + // Remove listeners. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput, 0}; + WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener( + _inputDeviceID, &propertyAddress, &objectListenerProc, this)); - propertyAddress.mSelector = kAudioDeviceProcessorOverload; - WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_inputDeviceID, - &propertyAddress, &objectListenerProc, this)); + propertyAddress.mSelector = kAudioDeviceProcessorOverload; + WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener( + _inputDeviceID, &propertyAddress, &objectListenerProc, this)); - _recIsInitialized = false; - _recording = false; + _recIsInitialized = false; + _recording = false; - return 0; + return 0; } -bool AudioDeviceMac::RecordingIsInitialized() const -{ - return (_recIsInitialized); +bool AudioDeviceMac::RecordingIsInitialized() const { + return (_recIsInitialized); } -bool AudioDeviceMac::Recording() const -{ - return (_recording); +bool AudioDeviceMac::Recording() const { + return (_recording); } -bool AudioDeviceMac::PlayoutIsInitialized() const -{ - return (_playIsInitialized); +bool AudioDeviceMac::PlayoutIsInitialized() const { + return (_playIsInitialized); } -int32_t AudioDeviceMac::StartPlayout() -{ +int32_t AudioDeviceMac::StartPlayout() { + CriticalSectionScoped lock(&_critSect); - CriticalSectionScoped lock(&_critSect); - - if (!_playIsInitialized) - { - return -1; - } + if (!_playIsInitialized) { + return -1; + } - if (_playing) - { - return 0; - } + if (_playing) { + return 0; + } - RTC_DCHECK(!render_worker_thread_.get()); - render_worker_thread_.reset( - new rtc::PlatformThread(RunRender, this, "RenderWorkerThread")); - render_worker_thread_->Start(); - render_worker_thread_->SetPriority(rtc::kRealtimePriority); + RTC_DCHECK(!render_worker_thread_.get()); + render_worker_thread_.reset( + new rtc::PlatformThread(RunRender, this, "RenderWorkerThread")); + render_worker_thread_->Start(); + render_worker_thread_->SetPriority(rtc::kRealtimePriority); - if (_twoDevices || !_recording) - { - OSStatus err = noErr; - WEBRTC_CA_RETURN_ON_ERR(AudioDeviceStart(_outputDeviceID, _deviceIOProcID)); - } - _playing = true; + if (_twoDevices || !_recording) { + OSStatus err = noErr; + WEBRTC_CA_RETURN_ON_ERR(AudioDeviceStart(_outputDeviceID, _deviceIOProcID)); + } + _playing = true; - return 0; + return 0; } -int32_t AudioDeviceMac::StopPlayout() -{ +int32_t AudioDeviceMac::StopPlayout() { + CriticalSectionScoped lock(&_critSect); - CriticalSectionScoped lock(&_critSect); + if (!_playIsInitialized) { + return 0; + } - if (!_playIsInitialized) - { - return 0; + OSStatus err = noErr; + + int32_t renderDeviceIsAlive = AtomicGet32(&_renderDeviceIsAlive); + if (_playing && renderDeviceIsAlive == 1) { + // We signal a stop for a shared device even when capturing has not + // yet ended. This is to ensure the IOProc will return early as + // intended (by checking |_playing|) before accessing resources we + // free below (e.g. the render converter). + // + // In the case of a shared device, the IOProc will verify capturing + // has ended before stopping itself. + _playing = false; + _doStop = true; // Signal to io proc to stop audio device + _critSect.Leave(); // Cannot be under lock, risk of deadlock + if (kEventTimeout == _stopEvent.Wait(2000)) { + CriticalSectionScoped critScoped(&_critSect); + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " Timed out stopping the render IOProc. " + "We may have failed to detect a device removal."); + + // We assume capturing on a shared device has stopped as well if the + // IOProc times out. + WEBRTC_CA_LOG_WARN(AudioDeviceStop(_outputDeviceID, _deviceIOProcID)); + WEBRTC_CA_LOG_WARN( + AudioDeviceDestroyIOProcID(_outputDeviceID, _deviceIOProcID)); } + _critSect.Enter(); + _doStop = false; + WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, "Playout stopped"); + } - OSStatus err = noErr; + // Setting this signal will allow the worker thread to be stopped. + AtomicSet32(&_renderDeviceIsAlive, 0); + if (render_worker_thread_.get()) { + _critSect.Leave(); + render_worker_thread_->Stop(); + render_worker_thread_.reset(); + _critSect.Enter(); + } - int32_t renderDeviceIsAlive = AtomicGet32(&_renderDeviceIsAlive); - if (_playing && renderDeviceIsAlive == 1) - { - // We signal a stop for a shared device even when capturing has not - // yet ended. This is to ensure the IOProc will return early as - // intended (by checking |_playing|) before accessing resources we - // free below (e.g. the render converter). - // - // In the case of a shared device, the IOProc will verify capturing - // has ended before stopping itself. - _playing = false; - _doStop = true; // Signal to io proc to stop audio device - _critSect.Leave(); // Cannot be under lock, risk of deadlock - if (kEventTimeout == _stopEvent.Wait(2000)) - { - CriticalSectionScoped critScoped(&_critSect); - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " Timed out stopping the render IOProc. " - "We may have failed to detect a device removal."); - - // We assume capturing on a shared device has stopped as well if the - // IOProc times out. - WEBRTC_CA_LOG_WARN(AudioDeviceStop(_outputDeviceID, - _deviceIOProcID)); - WEBRTC_CA_LOG_WARN(AudioDeviceDestroyIOProcID(_outputDeviceID, - _deviceIOProcID)); - } - _critSect.Enter(); - _doStop = false; - WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, - "Playout stopped"); - } + WEBRTC_CA_LOG_WARN(AudioConverterDispose(_renderConverter)); - // Setting this signal will allow the worker thread to be stopped. - AtomicSet32(&_renderDeviceIsAlive, 0); - if (render_worker_thread_.get()) { - _critSect.Leave(); - render_worker_thread_->Stop(); - render_worker_thread_.reset(); - _critSect.Enter(); - } + // Remove listeners. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeOutput, 0}; + WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener( + _outputDeviceID, &propertyAddress, &objectListenerProc, this)); - WEBRTC_CA_LOG_WARN(AudioConverterDispose(_renderConverter)); + propertyAddress.mSelector = kAudioDeviceProcessorOverload; + WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener( + _outputDeviceID, &propertyAddress, &objectListenerProc, this)); - // Remove listeners. - AudioObjectPropertyAddress propertyAddress = { - kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeOutput, - 0 }; - WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_outputDeviceID, - &propertyAddress, &objectListenerProc, this)); - - propertyAddress.mSelector = kAudioDeviceProcessorOverload; - WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_outputDeviceID, - &propertyAddress, &objectListenerProc, this)); - - if (_macBookPro) - { - Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID, - &propertyAddress); - if (hasProperty) - { - propertyAddress.mSelector = kAudioDevicePropertyDataSource; - WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_outputDeviceID, - &propertyAddress, &objectListenerProc, this)); - } + if (_macBookPro) { + Boolean hasProperty = + AudioObjectHasProperty(_outputDeviceID, &propertyAddress); + if (hasProperty) { + propertyAddress.mSelector = kAudioDevicePropertyDataSource; + WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener( + _outputDeviceID, &propertyAddress, &objectListenerProc, this)); } + } - _playIsInitialized = false; - _playing = false; + _playIsInitialized = false; + _playing = false; - return 0; + return 0; } -int32_t AudioDeviceMac::PlayoutDelay(uint16_t& delayMS) const -{ - int32_t renderDelayUs = AtomicGet32(&_renderDelayUs); - delayMS = static_cast<uint16_t> (1e-3 * (renderDelayUs + _renderLatencyUs) + - 0.5); - return 0; +int32_t AudioDeviceMac::PlayoutDelay(uint16_t& delayMS) const { + int32_t renderDelayUs = AtomicGet32(&_renderDelayUs); + delayMS = + static_cast<uint16_t>(1e-3 * (renderDelayUs + _renderLatencyUs) + 0.5); + return 0; } -int32_t AudioDeviceMac::RecordingDelay(uint16_t& delayMS) const -{ - int32_t captureDelayUs = AtomicGet32(&_captureDelayUs); - delayMS = static_cast<uint16_t> (1e-3 * (captureDelayUs + - _captureLatencyUs) + 0.5); - return 0; +int32_t AudioDeviceMac::RecordingDelay(uint16_t& delayMS) const { + int32_t captureDelayUs = AtomicGet32(&_captureDelayUs); + delayMS = + static_cast<uint16_t>(1e-3 * (captureDelayUs + _captureLatencyUs) + 0.5); + return 0; } -bool AudioDeviceMac::Playing() const -{ - return (_playing); +bool AudioDeviceMac::Playing() const { + return (_playing); } int32_t AudioDeviceMac::SetPlayoutBuffer( const AudioDeviceModule::BufferType type, - uint16_t sizeMS) -{ - - if (type != AudioDeviceModule::kFixedBufferSize) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " Adaptive buffer size not supported on this platform"); - return -1; - } + uint16_t sizeMS) { + if (type != AudioDeviceModule::kFixedBufferSize) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " Adaptive buffer size not supported on this platform"); + return -1; + } - _playBufType = type; - _playBufDelayFixed = sizeMS; - return 0; + _playBufType = type; + _playBufDelayFixed = sizeMS; + return 0; } -int32_t AudioDeviceMac::PlayoutBuffer( - AudioDeviceModule::BufferType& type, - uint16_t& sizeMS) const -{ - - type = _playBufType; - sizeMS = _playBufDelayFixed; +int32_t AudioDeviceMac::PlayoutBuffer(AudioDeviceModule::BufferType& type, + uint16_t& sizeMS) const { + type = _playBufType; + sizeMS = _playBufDelayFixed; - return 0; + return 0; } // Not implemented for Mac. -int32_t AudioDeviceMac::CPULoad(uint16_t& /*load*/) const -{ - - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " API call not supported on this platform"); +int32_t AudioDeviceMac::CPULoad(uint16_t& /*load*/) const { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " API call not supported on this platform"); - return -1; + return -1; } -bool AudioDeviceMac::PlayoutWarning() const -{ - return (_playWarning > 0); +bool AudioDeviceMac::PlayoutWarning() const { + return (_playWarning > 0); } -bool AudioDeviceMac::PlayoutError() const -{ - return (_playError > 0); +bool AudioDeviceMac::PlayoutError() const { + return (_playError > 0); } -bool AudioDeviceMac::RecordingWarning() const -{ - return (_recWarning > 0); +bool AudioDeviceMac::RecordingWarning() const { + return (_recWarning > 0); } -bool AudioDeviceMac::RecordingError() const -{ - return (_recError > 0); +bool AudioDeviceMac::RecordingError() const { + return (_recError > 0); } -void AudioDeviceMac::ClearPlayoutWarning() -{ - _playWarning = 0; +void AudioDeviceMac::ClearPlayoutWarning() { + _playWarning = 0; } -void AudioDeviceMac::ClearPlayoutError() -{ - _playError = 0; +void AudioDeviceMac::ClearPlayoutError() { + _playError = 0; } -void AudioDeviceMac::ClearRecordingWarning() -{ - _recWarning = 0; +void AudioDeviceMac::ClearRecordingWarning() { + _recWarning = 0; } -void AudioDeviceMac::ClearRecordingError() -{ - _recError = 0; +void AudioDeviceMac::ClearRecordingError() { + _recError = 0; } // ============================================================================ // Private Methods // ============================================================================ -int32_t -AudioDeviceMac::GetNumberDevices(const AudioObjectPropertyScope scope, - AudioDeviceID scopedDeviceIds[], - const uint32_t deviceListLength) -{ - OSStatus err = noErr; - - AudioObjectPropertyAddress propertyAddress = { - kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster }; - UInt32 size = 0; - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, - &propertyAddress, 0, NULL, &size)); - if (size == 0) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - "No devices"); - return 0; - } - - AudioDeviceID* deviceIds = (AudioDeviceID*) malloc(size); - UInt32 numberDevices = size / sizeof(AudioDeviceID); - AudioBufferList* bufferList = NULL; - UInt32 numberScopedDevices = 0; +int32_t AudioDeviceMac::GetNumberDevices(const AudioObjectPropertyScope scope, + AudioDeviceID scopedDeviceIds[], + const uint32_t deviceListLength) { + OSStatus err = noErr; + + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster}; + UInt32 size = 0; + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyDataSize( + kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size)); + if (size == 0) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "No devices"); + return 0; + } - // First check if there is a default device and list it - UInt32 hardwareProperty = 0; - if (scope == kAudioDevicePropertyScopeOutput) - { - hardwareProperty = kAudioHardwarePropertyDefaultOutputDevice; - } else - { - hardwareProperty = kAudioHardwarePropertyDefaultInputDevice; - } + AudioDeviceID* deviceIds = (AudioDeviceID*)malloc(size); + UInt32 numberDevices = size / sizeof(AudioDeviceID); + AudioBufferList* bufferList = NULL; + UInt32 numberScopedDevices = 0; + + // First check if there is a default device and list it + UInt32 hardwareProperty = 0; + if (scope == kAudioDevicePropertyScopeOutput) { + hardwareProperty = kAudioHardwarePropertyDefaultOutputDevice; + } else { + hardwareProperty = kAudioHardwarePropertyDefaultInputDevice; + } - AudioObjectPropertyAddress - propertyAddressDefault = { hardwareProperty, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster }; - - AudioDeviceID usedID; - UInt32 uintSize = sizeof(UInt32); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(kAudioObjectSystemObject, - &propertyAddressDefault, 0, NULL, &uintSize, &usedID)); - if (usedID != kAudioDeviceUnknown) - { - scopedDeviceIds[numberScopedDevices] = usedID; - numberScopedDevices++; - } else - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - "GetNumberDevices(): Default device unknown"); - } + AudioObjectPropertyAddress propertyAddressDefault = { + hardwareProperty, kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster}; + + AudioDeviceID usedID; + UInt32 uintSize = sizeof(UInt32); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(kAudioObjectSystemObject, + &propertyAddressDefault, 0, + NULL, &uintSize, &usedID)); + if (usedID != kAudioDeviceUnknown) { + scopedDeviceIds[numberScopedDevices] = usedID; + numberScopedDevices++; + } else { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + "GetNumberDevices(): Default device unknown"); + } - // Then list the rest of the devices - bool listOK = true; + // Then list the rest of the devices + bool listOK = true; - WEBRTC_CA_LOG_ERR(AudioObjectGetPropertyData(kAudioObjectSystemObject, - &propertyAddress, 0, NULL, &size, deviceIds)); - if (err != noErr) - { + WEBRTC_CA_LOG_ERR(AudioObjectGetPropertyData( + kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, deviceIds)); + if (err != noErr) { + listOK = false; + } else { + propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; + propertyAddress.mScope = scope; + propertyAddress.mElement = 0; + for (UInt32 i = 0; i < numberDevices; i++) { + // Check for input channels + WEBRTC_CA_LOG_ERR(AudioObjectGetPropertyDataSize( + deviceIds[i], &propertyAddress, 0, NULL, &size)); + if (err == kAudioHardwareBadDeviceError) { + // This device doesn't actually exist; continue iterating. + continue; + } else if (err != noErr) { listOK = false; - } else - { - propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; - propertyAddress.mScope = scope; - propertyAddress.mElement = 0; - for (UInt32 i = 0; i < numberDevices; i++) - { - // Check for input channels - WEBRTC_CA_LOG_ERR(AudioObjectGetPropertyDataSize(deviceIds[i], - &propertyAddress, 0, NULL, &size)); - if (err == kAudioHardwareBadDeviceError) - { - // This device doesn't actually exist; continue iterating. - continue; - } else if (err != noErr) - { - listOK = false; - break; - } - - bufferList = (AudioBufferList*) malloc(size); - WEBRTC_CA_LOG_ERR(AudioObjectGetPropertyData(deviceIds[i], - &propertyAddress, 0, NULL, &size, bufferList)); - if (err != noErr) - { - listOK = false; - break; - } - - if (bufferList->mNumberBuffers > 0) - { - if (numberScopedDevices >= deviceListLength) - { - WEBRTC_TRACE(kTraceError, - kTraceAudioDevice, _id, - "Device list is not long enough"); - listOK = false; - break; - } - - scopedDeviceIds[numberScopedDevices] = deviceIds[i]; - numberScopedDevices++; - } - - free(bufferList); - bufferList = NULL; - } // for - } + break; + } - if (!listOK) - { - if (deviceIds) - { - free(deviceIds); - deviceIds = NULL; + bufferList = (AudioBufferList*)malloc(size); + WEBRTC_CA_LOG_ERR(AudioObjectGetPropertyData( + deviceIds[i], &propertyAddress, 0, NULL, &size, bufferList)); + if (err != noErr) { + listOK = false; + break; + } + + if (bufferList->mNumberBuffers > 0) { + if (numberScopedDevices >= deviceListLength) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "Device list is not long enough"); + listOK = false; + break; } - if (bufferList) - { - free(bufferList); - bufferList = NULL; - } + scopedDeviceIds[numberScopedDevices] = deviceIds[i]; + numberScopedDevices++; + } - return -1; + free(bufferList); + bufferList = NULL; + } // for + } + + if (!listOK) { + if (deviceIds) { + free(deviceIds); + deviceIds = NULL; } - // Happy ending - if (deviceIds) - { - free(deviceIds); - deviceIds = NULL; + if (bufferList) { + free(bufferList); + bufferList = NULL; } - return numberScopedDevices; + return -1; + } + + // Happy ending + if (deviceIds) { + free(deviceIds); + deviceIds = NULL; + } + + return numberScopedDevices; } -int32_t -AudioDeviceMac::GetDeviceName(const AudioObjectPropertyScope scope, - const uint16_t index, - char* name) -{ - OSStatus err = noErr; - UInt32 len = kAdmMaxDeviceNameSize; - AudioDeviceID deviceIds[MaxNumberDevices]; - - int numberDevices = GetNumberDevices(scope, deviceIds, MaxNumberDevices); - if (numberDevices < 0) - { - return -1; - } else if (numberDevices == 0) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "No devices"); - return -1; - } +int32_t AudioDeviceMac::GetDeviceName(const AudioObjectPropertyScope scope, + const uint16_t index, + char* name) { + OSStatus err = noErr; + UInt32 len = kAdmMaxDeviceNameSize; + AudioDeviceID deviceIds[MaxNumberDevices]; - // If the number is below the number of devices, assume it's "WEBRTC ID" - // otherwise assume it's a CoreAudio ID - AudioDeviceID usedID; - - // Check if there is a default device - bool isDefaultDevice = false; - if (index == 0) - { - UInt32 hardwareProperty = 0; - if (scope == kAudioDevicePropertyScopeOutput) - { - hardwareProperty = kAudioHardwarePropertyDefaultOutputDevice; - } else - { - hardwareProperty = kAudioHardwarePropertyDefaultInputDevice; - } - AudioObjectPropertyAddress propertyAddress = { hardwareProperty, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster }; - UInt32 size = sizeof(UInt32); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(kAudioObjectSystemObject, - &propertyAddress, 0, NULL, &size, &usedID)); - if (usedID == kAudioDeviceUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - "GetDeviceName(): Default device unknown"); - } else - { - isDefaultDevice = true; - } - } + int numberDevices = GetNumberDevices(scope, deviceIds, MaxNumberDevices); + if (numberDevices < 0) { + return -1; + } else if (numberDevices == 0) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "No devices"); + return -1; + } + + // If the number is below the number of devices, assume it's "WEBRTC ID" + // otherwise assume it's a CoreAudio ID + AudioDeviceID usedID; + // Check if there is a default device + bool isDefaultDevice = false; + if (index == 0) { + UInt32 hardwareProperty = 0; + if (scope == kAudioDevicePropertyScopeOutput) { + hardwareProperty = kAudioHardwarePropertyDefaultOutputDevice; + } else { + hardwareProperty = kAudioHardwarePropertyDefaultInputDevice; + } AudioObjectPropertyAddress propertyAddress = { - kAudioDevicePropertyDeviceName, scope, 0 }; - - if (isDefaultDevice) - { - char devName[len]; - - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(usedID, - &propertyAddress, 0, NULL, &len, devName)); - - sprintf(name, "default (%s)", devName); - } else - { - if (index < numberDevices) - { - usedID = deviceIds[index]; - } else - { - usedID = index; - } + hardwareProperty, kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster}; + UInt32 size = sizeof(UInt32); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, &usedID)); + if (usedID == kAudioDeviceUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + "GetDeviceName(): Default device unknown"); + } else { + isDefaultDevice = true; + } + } - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(usedID, - &propertyAddress, 0, NULL, &len, name)); + AudioObjectPropertyAddress propertyAddress = {kAudioDevicePropertyDeviceName, + scope, 0}; + + if (isDefaultDevice) { + char devName[len]; + + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(usedID, &propertyAddress, + 0, NULL, &len, devName)); + + sprintf(name, "default (%s)", devName); + } else { + if (index < numberDevices) { + usedID = deviceIds[index]; + } else { + usedID = index; } - return 0; + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(usedID, &propertyAddress, + 0, NULL, &len, name)); + } + + return 0; } int32_t AudioDeviceMac::InitDevice(const uint16_t userDeviceIndex, AudioDeviceID& deviceId, - const bool isInput) -{ - OSStatus err = noErr; - UInt32 size = 0; - AudioObjectPropertyScope deviceScope; - AudioObjectPropertySelector defaultDeviceSelector; - AudioDeviceID deviceIds[MaxNumberDevices]; - - if (isInput) - { - deviceScope = kAudioDevicePropertyScopeInput; - defaultDeviceSelector = kAudioHardwarePropertyDefaultInputDevice; - } else - { - deviceScope = kAudioDevicePropertyScopeOutput; - defaultDeviceSelector = kAudioHardwarePropertyDefaultOutputDevice; - } + const bool isInput) { + OSStatus err = noErr; + UInt32 size = 0; + AudioObjectPropertyScope deviceScope; + AudioObjectPropertySelector defaultDeviceSelector; + AudioDeviceID deviceIds[MaxNumberDevices]; + + if (isInput) { + deviceScope = kAudioDevicePropertyScopeInput; + defaultDeviceSelector = kAudioHardwarePropertyDefaultInputDevice; + } else { + deviceScope = kAudioDevicePropertyScopeOutput; + defaultDeviceSelector = kAudioHardwarePropertyDefaultOutputDevice; + } - AudioObjectPropertyAddress - propertyAddress = { defaultDeviceSelector, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster }; - - // Get the actual device IDs - int numberDevices = GetNumberDevices(deviceScope, deviceIds, - MaxNumberDevices); - if (numberDevices < 0) - { - return -1; - } else if (numberDevices == 0) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "InitDevice(): No devices"); - return -1; - } + AudioObjectPropertyAddress propertyAddress = { + defaultDeviceSelector, kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster}; - bool isDefaultDevice = false; - deviceId = kAudioDeviceUnknown; - if (userDeviceIndex == 0) - { - // Try to use default system device - size = sizeof(AudioDeviceID); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(kAudioObjectSystemObject, - &propertyAddress, 0, NULL, &size, &deviceId)); - if (deviceId == kAudioDeviceUnknown) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " No default device exists"); - } else - { - isDefaultDevice = true; - } - } + // Get the actual device IDs + int numberDevices = + GetNumberDevices(deviceScope, deviceIds, MaxNumberDevices); + if (numberDevices < 0) { + return -1; + } else if (numberDevices == 0) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "InitDevice(): No devices"); + return -1; + } - if (!isDefaultDevice) - { - deviceId = deviceIds[userDeviceIndex]; + bool isDefaultDevice = false; + deviceId = kAudioDeviceUnknown; + if (userDeviceIndex == 0) { + // Try to use default system device + size = sizeof(AudioDeviceID); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, &deviceId)); + if (deviceId == kAudioDeviceUnknown) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " No default device exists"); + } else { + isDefaultDevice = true; } + } - // Obtain device name and manufacturer for logging. - // Also use this as a test to ensure a user-set device ID is valid. - char devName[128]; - char devManf[128]; - memset(devName, 0, sizeof(devName)); - memset(devManf, 0, sizeof(devManf)); - - propertyAddress.mSelector = kAudioDevicePropertyDeviceName; - propertyAddress.mScope = deviceScope; - propertyAddress.mElement = 0; - size = sizeof(devName); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(deviceId, - &propertyAddress, 0, NULL, &size, devName)); - - propertyAddress.mSelector = kAudioDevicePropertyDeviceManufacturer; - size = sizeof(devManf); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(deviceId, - &propertyAddress, 0, NULL, &size, devManf)); + if (!isDefaultDevice) { + deviceId = deviceIds[userDeviceIndex]; + } - if (isInput) - { - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " Input device: %s %s", devManf, devName); - } else - { - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " Output device: %s %s", devManf, devName); - } + // Obtain device name and manufacturer for logging. + // Also use this as a test to ensure a user-set device ID is valid. + char devName[128]; + char devManf[128]; + memset(devName, 0, sizeof(devName)); + memset(devManf, 0, sizeof(devManf)); + + propertyAddress.mSelector = kAudioDevicePropertyDeviceName; + propertyAddress.mScope = deviceScope; + propertyAddress.mElement = 0; + size = sizeof(devName); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(deviceId, &propertyAddress, + 0, NULL, &size, devName)); + + propertyAddress.mSelector = kAudioDevicePropertyDeviceManufacturer; + size = sizeof(devManf); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(deviceId, &propertyAddress, + 0, NULL, &size, devManf)); + + if (isInput) { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " Input device: %s %s", + devManf, devName); + } else { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " Output device: %s %s", + devManf, devName); + } - return 0; + return 0; } -OSStatus AudioDeviceMac::SetDesiredPlayoutFormat() -{ - // Our preferred format to work with. - _outDesiredFormat.mSampleRate = N_PLAY_SAMPLES_PER_SEC; - _outDesiredFormat.mChannelsPerFrame = _playChannels; +OSStatus AudioDeviceMac::SetDesiredPlayoutFormat() { + // Our preferred format to work with. + _outDesiredFormat.mSampleRate = N_PLAY_SAMPLES_PER_SEC; + _outDesiredFormat.mChannelsPerFrame = _playChannels; - if (_ptrAudioBuffer) - { - // Update audio buffer with the selected parameters. - _ptrAudioBuffer->SetPlayoutSampleRate(N_PLAY_SAMPLES_PER_SEC); - _ptrAudioBuffer->SetPlayoutChannels((uint8_t) _playChannels); - } + if (_ptrAudioBuffer) { + // Update audio buffer with the selected parameters. + _ptrAudioBuffer->SetPlayoutSampleRate(N_PLAY_SAMPLES_PER_SEC); + _ptrAudioBuffer->SetPlayoutChannels((uint8_t)_playChannels); + } - _renderDelayOffsetSamples = _renderBufSizeSamples - N_BUFFERS_OUT * - ENGINE_PLAY_BUF_SIZE_IN_SAMPLES * _outDesiredFormat.mChannelsPerFrame; + _renderDelayOffsetSamples = _renderBufSizeSamples - + N_BUFFERS_OUT * ENGINE_PLAY_BUF_SIZE_IN_SAMPLES * + _outDesiredFormat.mChannelsPerFrame; - _outDesiredFormat.mBytesPerPacket = _outDesiredFormat.mChannelsPerFrame * - sizeof(SInt16); - // In uncompressed audio, a packet is one frame. - _outDesiredFormat.mFramesPerPacket = 1; - _outDesiredFormat.mBytesPerFrame = _outDesiredFormat.mChannelsPerFrame * - sizeof(SInt16); - _outDesiredFormat.mBitsPerChannel = sizeof(SInt16) * 8; + _outDesiredFormat.mBytesPerPacket = + _outDesiredFormat.mChannelsPerFrame * sizeof(SInt16); + // In uncompressed audio, a packet is one frame. + _outDesiredFormat.mFramesPerPacket = 1; + _outDesiredFormat.mBytesPerFrame = + _outDesiredFormat.mChannelsPerFrame * sizeof(SInt16); + _outDesiredFormat.mBitsPerChannel = sizeof(SInt16) * 8; - _outDesiredFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | - kLinearPCMFormatFlagIsPacked; + _outDesiredFormat.mFormatFlags = + kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; #ifdef WEBRTC_ARCH_BIG_ENDIAN - _outDesiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; + _outDesiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; #endif - _outDesiredFormat.mFormatID = kAudioFormatLinearPCM; - - OSStatus err = noErr; - WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew(&_outDesiredFormat, - &_outStreamFormat, - &_renderConverter)); - - // Try to set buffer size to desired value (_playBufDelayFixed). - UInt32 bufByteCount = static_cast<UInt32> ((_outStreamFormat.mSampleRate / - 1000.0) * - _playBufDelayFixed * - _outStreamFormat.mChannelsPerFrame * - sizeof(Float32)); - if (_outStreamFormat.mFramesPerPacket != 0) - { - if (bufByteCount % _outStreamFormat.mFramesPerPacket != 0) - { - bufByteCount = (static_cast<UInt32> (bufByteCount / - _outStreamFormat.mFramesPerPacket) + 1) * - _outStreamFormat.mFramesPerPacket; - } - } - - // Ensure the buffer size is within the range provided by the device. - AudioObjectPropertyAddress propertyAddress = - {kAudioDevicePropertyDataSource, - kAudioDevicePropertyScopeOutput, - 0}; - propertyAddress.mSelector = kAudioDevicePropertyBufferSizeRange; - AudioValueRange range; - UInt32 size = sizeof(range); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, - 0, - NULL, - &size, - &range)); - if (range.mMinimum > bufByteCount) - { - bufByteCount = range.mMinimum; - } else if (range.mMaximum < bufByteCount) - { - bufByteCount = range.mMaximum; + _outDesiredFormat.mFormatID = kAudioFormatLinearPCM; + + OSStatus err = noErr; + WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew( + &_outDesiredFormat, &_outStreamFormat, &_renderConverter)); + + // Try to set buffer size to desired value (_playBufDelayFixed). + UInt32 bufByteCount = static_cast<UInt32>( + (_outStreamFormat.mSampleRate / 1000.0) * _playBufDelayFixed * + _outStreamFormat.mChannelsPerFrame * sizeof(Float32)); + if (_outStreamFormat.mFramesPerPacket != 0) { + if (bufByteCount % _outStreamFormat.mFramesPerPacket != 0) { + bufByteCount = (static_cast<UInt32>(bufByteCount / + _outStreamFormat.mFramesPerPacket) + + 1) * + _outStreamFormat.mFramesPerPacket; } + } - propertyAddress.mSelector = kAudioDevicePropertyBufferSize; - size = sizeof(bufByteCount); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, - &propertyAddress, - 0, - NULL, - size, - &bufByteCount)); - - // Get render device latency. - propertyAddress.mSelector = kAudioDevicePropertyLatency; - UInt32 latency = 0; - size = sizeof(UInt32); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, - 0, - NULL, - &size, - &latency)); - _renderLatencyUs = static_cast<uint32_t> ((1.0e6 * latency) / - _outStreamFormat.mSampleRate); - - // Get render stream latency. - propertyAddress.mSelector = kAudioDevicePropertyStreams; - AudioStreamID stream = 0; - size = sizeof(AudioStreamID); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, - 0, - NULL, - &size, - &stream)); - propertyAddress.mSelector = kAudioStreamPropertyLatency; - size = sizeof(UInt32); - latency = 0; - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, - &propertyAddress, - 0, - NULL, - &size, - &latency)); - _renderLatencyUs += static_cast<uint32_t> ((1.0e6 * latency) / - _outStreamFormat.mSampleRate); + // Ensure the buffer size is within the range provided by the device. + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyDataSource, kAudioDevicePropertyScopeOutput, 0}; + propertyAddress.mSelector = kAudioDevicePropertyBufferSizeRange; + AudioValueRange range; + UInt32 size = sizeof(range); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &range)); + if (range.mMinimum > bufByteCount) { + bufByteCount = range.mMinimum; + } else if (range.mMaximum < bufByteCount) { + bufByteCount = range.mMaximum; + } - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - " initial playout status: _renderDelayOffsetSamples=%d," - " _renderDelayUs=%d, _renderLatencyUs=%d", - _renderDelayOffsetSamples, _renderDelayUs, _renderLatencyUs); - return 0; + propertyAddress.mSelector = kAudioDevicePropertyBufferSize; + size = sizeof(bufByteCount); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, size, &bufByteCount)); + + // Get render device latency. + propertyAddress.mSelector = kAudioDevicePropertyLatency; + UInt32 latency = 0; + size = sizeof(UInt32); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &latency)); + _renderLatencyUs = + static_cast<uint32_t>((1.0e6 * latency) / _outStreamFormat.mSampleRate); + + // Get render stream latency. + propertyAddress.mSelector = kAudioDevicePropertyStreams; + AudioStreamID stream = 0; + size = sizeof(AudioStreamID); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &stream)); + propertyAddress.mSelector = kAudioStreamPropertyLatency; + size = sizeof(UInt32); + latency = 0; + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + _outputDeviceID, &propertyAddress, 0, NULL, &size, &latency)); + _renderLatencyUs += + static_cast<uint32_t>((1.0e6 * latency) / _outStreamFormat.mSampleRate); + + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + " initial playout status: _renderDelayOffsetSamples=%d," + " _renderDelayUs=%d, _renderLatencyUs=%d", + _renderDelayOffsetSamples, _renderDelayUs, _renderLatencyUs); + return 0; } OSStatus AudioDeviceMac::objectListenerProc( AudioObjectID objectId, UInt32 numberAddresses, const AudioObjectPropertyAddress addresses[], - void* clientData) -{ - AudioDeviceMac *ptrThis = (AudioDeviceMac *) clientData; - RTC_DCHECK(ptrThis != NULL); + void* clientData) { + AudioDeviceMac* ptrThis = (AudioDeviceMac*)clientData; + RTC_DCHECK(ptrThis != NULL); - ptrThis->implObjectListenerProc(objectId, numberAddresses, addresses); + ptrThis->implObjectListenerProc(objectId, numberAddresses, addresses); - // AudioObjectPropertyListenerProc functions are supposed to return 0 - return 0; + // AudioObjectPropertyListenerProc functions are supposed to return 0 + return 0; } OSStatus AudioDeviceMac::implObjectListenerProc( const AudioObjectID objectId, const UInt32 numberAddresses, - const AudioObjectPropertyAddress addresses[]) -{ - WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, - "AudioDeviceMac::implObjectListenerProc()"); - - for (UInt32 i = 0; i < numberAddresses; i++) - { - if (addresses[i].mSelector == kAudioHardwarePropertyDevices) - { - HandleDeviceChange(); - } else if (addresses[i].mSelector == kAudioDevicePropertyStreamFormat) - { - HandleStreamFormatChange(objectId, addresses[i]); - } else if (addresses[i].mSelector == kAudioDevicePropertyDataSource) - { - HandleDataSourceChange(objectId, addresses[i]); - } else if (addresses[i].mSelector == kAudioDeviceProcessorOverload) - { - HandleProcessorOverload(addresses[i]); - } + const AudioObjectPropertyAddress addresses[]) { + WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, + "AudioDeviceMac::implObjectListenerProc()"); + + for (UInt32 i = 0; i < numberAddresses; i++) { + if (addresses[i].mSelector == kAudioHardwarePropertyDevices) { + HandleDeviceChange(); + } else if (addresses[i].mSelector == kAudioDevicePropertyStreamFormat) { + HandleStreamFormatChange(objectId, addresses[i]); + } else if (addresses[i].mSelector == kAudioDevicePropertyDataSource) { + HandleDataSourceChange(objectId, addresses[i]); + } else if (addresses[i].mSelector == kAudioDeviceProcessorOverload) { + HandleProcessorOverload(addresses[i]); } + } - return 0; + return 0; } -int32_t AudioDeviceMac::HandleDeviceChange() -{ - OSStatus err = noErr; +int32_t AudioDeviceMac::HandleDeviceChange() { + OSStatus err = noErr; - WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, - "kAudioHardwarePropertyDevices"); - - // A device has changed. Check if our registered devices have been removed. - // Ensure the devices have been initialized, meaning the IDs are valid. - if (MicrophoneIsInitialized()) - { - AudioObjectPropertyAddress propertyAddress = { - kAudioDevicePropertyDeviceIsAlive, - kAudioDevicePropertyScopeInput, 0 }; - UInt32 deviceIsAlive = 1; - UInt32 size = sizeof(UInt32); - err = AudioObjectGetPropertyData(_inputDeviceID, &propertyAddress, 0, - NULL, &size, &deviceIsAlive); - - if (err == kAudioHardwareBadDeviceError || deviceIsAlive == 0) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - "Capture device is not alive (probably removed)"); - AtomicSet32(&_captureDeviceIsAlive, 0); - _mixerManager.CloseMicrophone(); - if (_recError == 1) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, - _id, " pending recording error exists"); - } - _recError = 1; // triggers callback from module process thread - } else if (err != noErr) - { - logCAMsg(kTraceError, kTraceAudioDevice, _id, - "Error in AudioDeviceGetProperty()", (const char*) &err); - return -1; - } + WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, + "kAudioHardwarePropertyDevices"); + + // A device has changed. Check if our registered devices have been removed. + // Ensure the devices have been initialized, meaning the IDs are valid. + if (MicrophoneIsInitialized()) { + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyDeviceIsAlive, kAudioDevicePropertyScopeInput, 0}; + UInt32 deviceIsAlive = 1; + UInt32 size = sizeof(UInt32); + err = AudioObjectGetPropertyData(_inputDeviceID, &propertyAddress, 0, NULL, + &size, &deviceIsAlive); + + if (err == kAudioHardwareBadDeviceError || deviceIsAlive == 0) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + "Capture device is not alive (probably removed)"); + AtomicSet32(&_captureDeviceIsAlive, 0); + _mixerManager.CloseMicrophone(); + if (_recError == 1) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " pending recording error exists"); + } + _recError = 1; // triggers callback from module process thread + } else if (err != noErr) { + logCAMsg(kTraceError, kTraceAudioDevice, _id, + "Error in AudioDeviceGetProperty()", (const char*)&err); + return -1; } + } - if (SpeakerIsInitialized()) - { - AudioObjectPropertyAddress propertyAddress = { - kAudioDevicePropertyDeviceIsAlive, - kAudioDevicePropertyScopeOutput, 0 }; - UInt32 deviceIsAlive = 1; - UInt32 size = sizeof(UInt32); - err = AudioObjectGetPropertyData(_outputDeviceID, &propertyAddress, 0, - NULL, &size, &deviceIsAlive); - - if (err == kAudioHardwareBadDeviceError || deviceIsAlive == 0) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - "Render device is not alive (probably removed)"); - AtomicSet32(&_renderDeviceIsAlive, 0); - _mixerManager.CloseSpeaker(); - if (_playError == 1) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, - _id, " pending playout error exists"); - } - _playError = 1; // triggers callback from module process thread - } else if (err != noErr) - { - logCAMsg(kTraceError, kTraceAudioDevice, _id, - "Error in AudioDeviceGetProperty()", (const char*) &err); - return -1; - } + if (SpeakerIsInitialized()) { + AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyDeviceIsAlive, kAudioDevicePropertyScopeOutput, 0}; + UInt32 deviceIsAlive = 1; + UInt32 size = sizeof(UInt32); + err = AudioObjectGetPropertyData(_outputDeviceID, &propertyAddress, 0, NULL, + &size, &deviceIsAlive); + + if (err == kAudioHardwareBadDeviceError || deviceIsAlive == 0) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + "Render device is not alive (probably removed)"); + AtomicSet32(&_renderDeviceIsAlive, 0); + _mixerManager.CloseSpeaker(); + if (_playError == 1) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " pending playout error exists"); + } + _playError = 1; // triggers callback from module process thread + } else if (err != noErr) { + logCAMsg(kTraceError, kTraceAudioDevice, _id, + "Error in AudioDeviceGetProperty()", (const char*)&err); + return -1; } + } - return 0; + return 0; } int32_t AudioDeviceMac::HandleStreamFormatChange( const AudioObjectID objectId, - const AudioObjectPropertyAddress propertyAddress) -{ - OSStatus err = noErr; + const AudioObjectPropertyAddress propertyAddress) { + OSStatus err = noErr; - WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, - "Stream format changed"); + WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, "Stream format changed"); - if (objectId != _inputDeviceID && objectId != _outputDeviceID) - { - return 0; - } - - // Get the new device format - AudioStreamBasicDescription streamFormat; - UInt32 size = sizeof(streamFormat); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(objectId, - &propertyAddress, 0, NULL, &size, &streamFormat)); - - if (streamFormat.mFormatID != kAudioFormatLinearPCM) - { - logCAMsg(kTraceError, kTraceAudioDevice, _id, - "Unacceptable input stream format -> mFormatID", - (const char *) &streamFormat.mFormatID); - return -1; - } - - if (streamFormat.mChannelsPerFrame > N_DEVICE_CHANNELS) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "Too many channels on device (mChannelsPerFrame = %d)", - streamFormat.mChannelsPerFrame); - return -1; - } + if (objectId != _inputDeviceID && objectId != _outputDeviceID) { + return 0; + } - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "Stream format:"); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "mSampleRate = %f, mChannelsPerFrame = %u", - streamFormat.mSampleRate, streamFormat.mChannelsPerFrame); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "mBytesPerPacket = %u, mFramesPerPacket = %u", - streamFormat.mBytesPerPacket, streamFormat.mFramesPerPacket); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "mBytesPerFrame = %u, mBitsPerChannel = %u", - streamFormat.mBytesPerFrame, streamFormat.mBitsPerChannel); - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "mFormatFlags = %u", - streamFormat.mFormatFlags); - logCAMsg(kTraceInfo, kTraceAudioDevice, _id, "mFormatID", - (const char *) &streamFormat.mFormatID); - - if (propertyAddress.mScope == kAudioDevicePropertyScopeInput) - { - const int io_block_size_samples = streamFormat.mChannelsPerFrame * - streamFormat.mSampleRate / 100 * N_BLOCKS_IO; - if (io_block_size_samples > _captureBufSizeSamples) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - "Input IO block size (%d) is larger than ring buffer (%u)", - io_block_size_samples, _captureBufSizeSamples); - return -1; + // Get the new device format + AudioStreamBasicDescription streamFormat; + UInt32 size = sizeof(streamFormat); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + objectId, &propertyAddress, 0, NULL, &size, &streamFormat)); - } + if (streamFormat.mFormatID != kAudioFormatLinearPCM) { + logCAMsg(kTraceError, kTraceAudioDevice, _id, + "Unacceptable input stream format -> mFormatID", + (const char*)&streamFormat.mFormatID); + return -1; + } - memcpy(&_inStreamFormat, &streamFormat, sizeof(streamFormat)); - - if (_inStreamFormat.mChannelsPerFrame >= 2 && (_recChannels == 2)) - { - _inDesiredFormat.mChannelsPerFrame = 2; - } else - { - // Disable stereo recording when we only have one channel on the device. - _inDesiredFormat.mChannelsPerFrame = 1; - _recChannels = 1; - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "Stereo recording unavailable on this device"); - } + if (streamFormat.mChannelsPerFrame > N_DEVICE_CHANNELS) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "Too many channels on device (mChannelsPerFrame = %d)", + streamFormat.mChannelsPerFrame); + return -1; + } - if (_ptrAudioBuffer) - { - // Update audio buffer with the selected parameters - _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); - _ptrAudioBuffer->SetRecordingChannels((uint8_t) _recChannels); - } + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Stream format:"); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "mSampleRate = %f, mChannelsPerFrame = %u", + streamFormat.mSampleRate, streamFormat.mChannelsPerFrame); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "mBytesPerPacket = %u, mFramesPerPacket = %u", + streamFormat.mBytesPerPacket, streamFormat.mFramesPerPacket); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "mBytesPerFrame = %u, mBitsPerChannel = %u", + streamFormat.mBytesPerFrame, streamFormat.mBitsPerChannel); + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "mFormatFlags = %u", + streamFormat.mFormatFlags); + logCAMsg(kTraceInfo, kTraceAudioDevice, _id, "mFormatID", + (const char*)&streamFormat.mFormatID); + + if (propertyAddress.mScope == kAudioDevicePropertyScopeInput) { + const int io_block_size_samples = streamFormat.mChannelsPerFrame * + streamFormat.mSampleRate / 100 * + N_BLOCKS_IO; + if (io_block_size_samples > _captureBufSizeSamples) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + "Input IO block size (%d) is larger than ring buffer (%u)", + io_block_size_samples, _captureBufSizeSamples); + return -1; + } + + memcpy(&_inStreamFormat, &streamFormat, sizeof(streamFormat)); + + if (_inStreamFormat.mChannelsPerFrame >= 2 && (_recChannels == 2)) { + _inDesiredFormat.mChannelsPerFrame = 2; + } else { + // Disable stereo recording when we only have one channel on the device. + _inDesiredFormat.mChannelsPerFrame = 1; + _recChannels = 1; + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "Stereo recording unavailable on this device"); + } + + if (_ptrAudioBuffer) { + // Update audio buffer with the selected parameters + _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); + _ptrAudioBuffer->SetRecordingChannels((uint8_t)_recChannels); + } + + // Recreate the converter with the new format + // TODO(xians): make this thread safe + WEBRTC_CA_RETURN_ON_ERR(AudioConverterDispose(_captureConverter)); + + WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew(&streamFormat, &_inDesiredFormat, + &_captureConverter)); + } else { + memcpy(&_outStreamFormat, &streamFormat, sizeof(streamFormat)); - // Recreate the converter with the new format - // TODO(xians): make this thread safe - WEBRTC_CA_RETURN_ON_ERR(AudioConverterDispose(_captureConverter)); - - WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew(&streamFormat, &_inDesiredFormat, - &_captureConverter)); - } else - { - memcpy(&_outStreamFormat, &streamFormat, sizeof(streamFormat)); - - // Our preferred format to work with - if (_outStreamFormat.mChannelsPerFrame < 2) - { - _playChannels = 1; - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "Stereo playout unavailable on this device"); - } - WEBRTC_CA_RETURN_ON_ERR(SetDesiredPlayoutFormat()); + // Our preferred format to work with + if (_outStreamFormat.mChannelsPerFrame < 2) { + _playChannels = 1; + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "Stereo playout unavailable on this device"); } - return 0; + WEBRTC_CA_RETURN_ON_ERR(SetDesiredPlayoutFormat()); + } + return 0; } int32_t AudioDeviceMac::HandleDataSourceChange( const AudioObjectID objectId, - const AudioObjectPropertyAddress propertyAddress) -{ - OSStatus err = noErr; + const AudioObjectPropertyAddress propertyAddress) { + OSStatus err = noErr; - if (_macBookPro && propertyAddress.mScope - == kAudioDevicePropertyScopeOutput) - { - WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, - "Data source changed"); - - _macBookProPanRight = false; - UInt32 dataSource = 0; - UInt32 size = sizeof(UInt32); - WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(objectId, - &propertyAddress, 0, NULL, &size, &dataSource)); - if (dataSource == 'ispk') - { - _macBookProPanRight = true; - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "MacBook Pro using internal speakers; stereo panning right"); - } else - { - WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, - "MacBook Pro not using internal speakers"); - } + if (_macBookPro && + propertyAddress.mScope == kAudioDevicePropertyScopeOutput) { + WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, "Data source changed"); + + _macBookProPanRight = false; + UInt32 dataSource = 0; + UInt32 size = sizeof(UInt32); + WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( + objectId, &propertyAddress, 0, NULL, &size, &dataSource)); + if (dataSource == 'ispk') { + _macBookProPanRight = true; + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "MacBook Pro using internal speakers; stereo panning right"); + } else { + WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, + "MacBook Pro not using internal speakers"); } + } - return 0; + return 0; } int32_t AudioDeviceMac::HandleProcessorOverload( - const AudioObjectPropertyAddress propertyAddress) -{ - // TODO(xians): we probably want to notify the user in some way of the - // overload. However, the Windows interpretations of these errors seem to - // be more severe than what ProcessorOverload is thrown for. - // - // We don't log the notification, as it's sent from the HAL's IO thread. We - // don't want to slow it down even further. - if (propertyAddress.mScope == kAudioDevicePropertyScopeInput) - { - //WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "Capture processor - // overload"); - //_callback->ProblemIsReported( - // SndCardStreamObserver::ERecordingProblem); - } else - { - //WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - // "Render processor overload"); - //_callback->ProblemIsReported( - // SndCardStreamObserver::EPlaybackProblem); - } + const AudioObjectPropertyAddress propertyAddress) { + // TODO(xians): we probably want to notify the user in some way of the + // overload. However, the Windows interpretations of these errors seem to + // be more severe than what ProcessorOverload is thrown for. + // + // We don't log the notification, as it's sent from the HAL's IO thread. We + // don't want to slow it down even further. + if (propertyAddress.mScope == kAudioDevicePropertyScopeInput) { + // WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "Capture processor + // overload"); + //_callback->ProblemIsReported( + // SndCardStreamObserver::ERecordingProblem); + } else { + // WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + // "Render processor overload"); + //_callback->ProblemIsReported( + // SndCardStreamObserver::EPlaybackProblem); + } - return 0; + return 0; } // ============================================================================ // Thread Methods // ============================================================================ -OSStatus AudioDeviceMac::deviceIOProc(AudioDeviceID, const AudioTimeStamp*, +OSStatus AudioDeviceMac::deviceIOProc(AudioDeviceID, + const AudioTimeStamp*, const AudioBufferList* inputData, const AudioTimeStamp* inputTime, AudioBufferList* outputData, const AudioTimeStamp* outputTime, - void *clientData) -{ - AudioDeviceMac *ptrThis = (AudioDeviceMac *) clientData; - RTC_DCHECK(ptrThis != NULL); + void* clientData) { + AudioDeviceMac* ptrThis = (AudioDeviceMac*)clientData; + RTC_DCHECK(ptrThis != NULL); - ptrThis->implDeviceIOProc(inputData, inputTime, outputData, outputTime); + ptrThis->implDeviceIOProc(inputData, inputTime, outputData, outputTime); - // AudioDeviceIOProc functions are supposed to return 0 - return 0; + // AudioDeviceIOProc functions are supposed to return 0 + return 0; } OSStatus AudioDeviceMac::outConverterProc(AudioConverterRef, - UInt32 *numberDataPackets, - AudioBufferList *data, - AudioStreamPacketDescription **, - void *userData) -{ - AudioDeviceMac *ptrThis = (AudioDeviceMac *) userData; - RTC_DCHECK(ptrThis != NULL); + UInt32* numberDataPackets, + AudioBufferList* data, + AudioStreamPacketDescription**, + void* userData) { + AudioDeviceMac* ptrThis = (AudioDeviceMac*)userData; + RTC_DCHECK(ptrThis != NULL); - return ptrThis->implOutConverterProc(numberDataPackets, data); + return ptrThis->implOutConverterProc(numberDataPackets, data); } -OSStatus AudioDeviceMac::inDeviceIOProc(AudioDeviceID, const AudioTimeStamp*, +OSStatus AudioDeviceMac::inDeviceIOProc(AudioDeviceID, + const AudioTimeStamp*, const AudioBufferList* inputData, const AudioTimeStamp* inputTime, AudioBufferList*, - const AudioTimeStamp*, void* clientData) -{ - AudioDeviceMac *ptrThis = (AudioDeviceMac *) clientData; - RTC_DCHECK(ptrThis != NULL); + const AudioTimeStamp*, + void* clientData) { + AudioDeviceMac* ptrThis = (AudioDeviceMac*)clientData; + RTC_DCHECK(ptrThis != NULL); - ptrThis->implInDeviceIOProc(inputData, inputTime); + ptrThis->implInDeviceIOProc(inputData, inputTime); - // AudioDeviceIOProc functions are supposed to return 0 - return 0; + // AudioDeviceIOProc functions are supposed to return 0 + return 0; } OSStatus AudioDeviceMac::inConverterProc( AudioConverterRef, - UInt32 *numberDataPackets, - AudioBufferList *data, - AudioStreamPacketDescription ** /*dataPacketDescription*/, - void *userData) -{ - AudioDeviceMac *ptrThis = static_cast<AudioDeviceMac*> (userData); - RTC_DCHECK(ptrThis != NULL); - - return ptrThis->implInConverterProc(numberDataPackets, data); -} - -OSStatus AudioDeviceMac::implDeviceIOProc(const AudioBufferList *inputData, - const AudioTimeStamp *inputTime, - AudioBufferList *outputData, - const AudioTimeStamp *outputTime) -{ - OSStatus err = noErr; - UInt64 outputTimeNs = AudioConvertHostTimeToNanos(outputTime->mHostTime); - UInt64 nowNs = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); - - if (!_twoDevices && _recording) - { - implInDeviceIOProc(inputData, inputTime); - } + UInt32* numberDataPackets, + AudioBufferList* data, + AudioStreamPacketDescription** /*dataPacketDescription*/, + void* userData) { + AudioDeviceMac* ptrThis = static_cast<AudioDeviceMac*>(userData); + RTC_DCHECK(ptrThis != NULL); + + return ptrThis->implInConverterProc(numberDataPackets, data); +} + +OSStatus AudioDeviceMac::implDeviceIOProc(const AudioBufferList* inputData, + const AudioTimeStamp* inputTime, + AudioBufferList* outputData, + const AudioTimeStamp* outputTime) { + OSStatus err = noErr; + UInt64 outputTimeNs = AudioConvertHostTimeToNanos(outputTime->mHostTime); + UInt64 nowNs = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); + + if (!_twoDevices && _recording) { + implInDeviceIOProc(inputData, inputTime); + } - // Check if we should close down audio device - // Double-checked locking optimization to remove locking overhead - if (_doStop) - { - _critSect.Enter(); - if (_doStop) - { - if (_twoDevices || (!_recording && !_playing)) - { - // In the case of a shared device, the single driving ioProc - // is stopped here - WEBRTC_CA_LOG_ERR(AudioDeviceStop(_outputDeviceID, - _deviceIOProcID)); - WEBRTC_CA_LOG_WARN(AudioDeviceDestroyIOProcID(_outputDeviceID, - _deviceIOProcID)); - if (err == noErr) - { - WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, - _id, " Playout or shared device stopped"); - } - } - - _doStop = false; - _stopEvent.Set(); - _critSect.Leave(); - return 0; + // Check if we should close down audio device + // Double-checked locking optimization to remove locking overhead + if (_doStop) { + _critSect.Enter(); + if (_doStop) { + if (_twoDevices || (!_recording && !_playing)) { + // In the case of a shared device, the single driving ioProc + // is stopped here + WEBRTC_CA_LOG_ERR(AudioDeviceStop(_outputDeviceID, _deviceIOProcID)); + WEBRTC_CA_LOG_WARN( + AudioDeviceDestroyIOProcID(_outputDeviceID, _deviceIOProcID)); + if (err == noErr) { + WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, + " Playout or shared device stopped"); } - _critSect.Leave(); - } + } - if (!_playing) - { - // This can be the case when a shared device is capturing but not - // rendering. We allow the checks above before returning to avoid a - // timeout when capturing is stopped. - return 0; + _doStop = false; + _stopEvent.Set(); + _critSect.Leave(); + return 0; } + _critSect.Leave(); + } - RTC_DCHECK(_outStreamFormat.mBytesPerFrame != 0); - UInt32 size = outputData->mBuffers->mDataByteSize - / _outStreamFormat.mBytesPerFrame; - - // TODO(xians): signal an error somehow? - err = AudioConverterFillComplexBuffer(_renderConverter, outConverterProc, - this, &size, outputData, NULL); - if (err != noErr) - { - if (err == 1) - { - // This is our own error. - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " Error in AudioConverterFillComplexBuffer()"); - return 1; - } else - { - logCAMsg(kTraceError, kTraceAudioDevice, _id, - "Error in AudioConverterFillComplexBuffer()", - (const char *) &err); - return 1; - } + if (!_playing) { + // This can be the case when a shared device is capturing but not + // rendering. We allow the checks above before returning to avoid a + // timeout when capturing is stopped. + return 0; + } + + RTC_DCHECK(_outStreamFormat.mBytesPerFrame != 0); + UInt32 size = + outputData->mBuffers->mDataByteSize / _outStreamFormat.mBytesPerFrame; + + // TODO(xians): signal an error somehow? + err = AudioConverterFillComplexBuffer(_renderConverter, outConverterProc, + this, &size, outputData, NULL); + if (err != noErr) { + if (err == 1) { + // This is our own error. + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " Error in AudioConverterFillComplexBuffer()"); + return 1; + } else { + logCAMsg(kTraceError, kTraceAudioDevice, _id, + "Error in AudioConverterFillComplexBuffer()", (const char*)&err); + return 1; } + } - PaRingBufferSize bufSizeSamples = - PaUtil_GetRingBufferReadAvailable(_paRenderBuffer); + PaRingBufferSize bufSizeSamples = + PaUtil_GetRingBufferReadAvailable(_paRenderBuffer); - int32_t renderDelayUs = static_cast<int32_t> (1e-3 * (outputTimeNs - nowNs) - + 0.5); - renderDelayUs += static_cast<int32_t> ((1.0e6 * bufSizeSamples) - / _outDesiredFormat.mChannelsPerFrame / _outDesiredFormat.mSampleRate - + 0.5); + int32_t renderDelayUs = + static_cast<int32_t>(1e-3 * (outputTimeNs - nowNs) + 0.5); + renderDelayUs += static_cast<int32_t>( + (1.0e6 * bufSizeSamples) / _outDesiredFormat.mChannelsPerFrame / + _outDesiredFormat.mSampleRate + + 0.5); - AtomicSet32(&_renderDelayUs, renderDelayUs); + AtomicSet32(&_renderDelayUs, renderDelayUs); - return 0; + return 0; } -OSStatus AudioDeviceMac::implOutConverterProc(UInt32 *numberDataPackets, - AudioBufferList *data) -{ +OSStatus AudioDeviceMac::implOutConverterProc(UInt32* numberDataPackets, + AudioBufferList* data) { RTC_DCHECK(data->mNumberBuffers == 1); - PaRingBufferSize numSamples = *numberDataPackets - * _outDesiredFormat.mChannelsPerFrame; - - data->mBuffers->mNumberChannels = _outDesiredFormat.mChannelsPerFrame; - // Always give the converter as much as it wants, zero padding as required. - data->mBuffers->mDataByteSize = *numberDataPackets - * _outDesiredFormat.mBytesPerPacket; - data->mBuffers->mData = _renderConvertData; - memset(_renderConvertData, 0, sizeof(_renderConvertData)); - - PaUtil_ReadRingBuffer(_paRenderBuffer, _renderConvertData, numSamples); - - kern_return_t kernErr = semaphore_signal_all(_renderSemaphore); - if (kernErr != KERN_SUCCESS) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " semaphore_signal_all() error: %d", kernErr); - return 1; - } + PaRingBufferSize numSamples = + *numberDataPackets * _outDesiredFormat.mChannelsPerFrame; - return 0; + data->mBuffers->mNumberChannels = _outDesiredFormat.mChannelsPerFrame; + // Always give the converter as much as it wants, zero padding as required. + data->mBuffers->mDataByteSize = + *numberDataPackets * _outDesiredFormat.mBytesPerPacket; + data->mBuffers->mData = _renderConvertData; + memset(_renderConvertData, 0, sizeof(_renderConvertData)); + + PaUtil_ReadRingBuffer(_paRenderBuffer, _renderConvertData, numSamples); + + kern_return_t kernErr = semaphore_signal_all(_renderSemaphore); + if (kernErr != KERN_SUCCESS) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " semaphore_signal_all() error: %d", kernErr); + return 1; + } + + return 0; } -OSStatus AudioDeviceMac::implInDeviceIOProc(const AudioBufferList *inputData, - const AudioTimeStamp *inputTime) -{ - OSStatus err = noErr; - UInt64 inputTimeNs = AudioConvertHostTimeToNanos(inputTime->mHostTime); - UInt64 nowNs = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); - - // Check if we should close down audio device - // Double-checked locking optimization to remove locking overhead - if (_doStopRec) - { - _critSect.Enter(); - if (_doStopRec) - { - // This will be signalled only when a shared device is not in use. - WEBRTC_CA_LOG_ERR(AudioDeviceStop(_inputDeviceID, _inDeviceIOProcID)); - WEBRTC_CA_LOG_WARN(AudioDeviceDestroyIOProcID(_inputDeviceID, - _inDeviceIOProcID)); - if (err == noErr) - { - WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, - _id, " Recording device stopped"); - } - - _doStopRec = false; - _stopEventRec.Set(); - _critSect.Leave(); - return 0; - } - _critSect.Leave(); - } +OSStatus AudioDeviceMac::implInDeviceIOProc(const AudioBufferList* inputData, + const AudioTimeStamp* inputTime) { + OSStatus err = noErr; + UInt64 inputTimeNs = AudioConvertHostTimeToNanos(inputTime->mHostTime); + UInt64 nowNs = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); - if (!_recording) - { - // Allow above checks to avoid a timeout on stopping capture. - return 0; - } + // Check if we should close down audio device + // Double-checked locking optimization to remove locking overhead + if (_doStopRec) { + _critSect.Enter(); + if (_doStopRec) { + // This will be signalled only when a shared device is not in use. + WEBRTC_CA_LOG_ERR(AudioDeviceStop(_inputDeviceID, _inDeviceIOProcID)); + WEBRTC_CA_LOG_WARN( + AudioDeviceDestroyIOProcID(_inputDeviceID, _inDeviceIOProcID)); + if (err == noErr) { + WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, + " Recording device stopped"); + } - PaRingBufferSize bufSizeSamples = - PaUtil_GetRingBufferReadAvailable(_paCaptureBuffer); - - int32_t captureDelayUs = static_cast<int32_t> (1e-3 * (nowNs - inputTimeNs) - + 0.5); - captureDelayUs - += static_cast<int32_t> ((1.0e6 * bufSizeSamples) - / _inStreamFormat.mChannelsPerFrame / _inStreamFormat.mSampleRate - + 0.5); - - AtomicSet32(&_captureDelayUs, captureDelayUs); - - RTC_DCHECK(inputData->mNumberBuffers == 1); - PaRingBufferSize numSamples = inputData->mBuffers->mDataByteSize - * _inStreamFormat.mChannelsPerFrame / _inStreamFormat.mBytesPerPacket; - PaUtil_WriteRingBuffer(_paCaptureBuffer, inputData->mBuffers->mData, - numSamples); - - kern_return_t kernErr = semaphore_signal_all(_captureSemaphore); - if (kernErr != KERN_SUCCESS) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " semaphore_signal_all() error: %d", kernErr); + _doStopRec = false; + _stopEventRec.Set(); + _critSect.Leave(); + return 0; } + _critSect.Leave(); + } - return err; -} + if (!_recording) { + // Allow above checks to avoid a timeout on stopping capture. + return 0; + } -OSStatus AudioDeviceMac::implInConverterProc(UInt32 *numberDataPackets, - AudioBufferList *data) -{ - RTC_DCHECK(data->mNumberBuffers == 1); - PaRingBufferSize numSamples = *numberDataPackets - * _inStreamFormat.mChannelsPerFrame; - - while (PaUtil_GetRingBufferReadAvailable(_paCaptureBuffer) < numSamples) - { - mach_timespec_t timeout; - timeout.tv_sec = 0; - timeout.tv_nsec = TIMER_PERIOD_MS; - - kern_return_t kernErr = semaphore_timedwait(_captureSemaphore, timeout); - if (kernErr == KERN_OPERATION_TIMED_OUT) - { - int32_t signal = AtomicGet32(&_captureDeviceIsAlive); - if (signal == 0) - { - // The capture device is no longer alive; stop the worker thread. - *numberDataPackets = 0; - return 1; - } - } else if (kernErr != KERN_SUCCESS) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " semaphore_wait() error: %d", kernErr); - } - } + PaRingBufferSize bufSizeSamples = + PaUtil_GetRingBufferReadAvailable(_paCaptureBuffer); - // Pass the read pointer directly to the converter to avoid a memcpy. - void* dummyPtr; - PaRingBufferSize dummySize; - PaUtil_GetRingBufferReadRegions(_paCaptureBuffer, numSamples, - &data->mBuffers->mData, &numSamples, - &dummyPtr, &dummySize); - PaUtil_AdvanceRingBufferReadIndex(_paCaptureBuffer, numSamples); + int32_t captureDelayUs = + static_cast<int32_t>(1e-3 * (nowNs - inputTimeNs) + 0.5); + captureDelayUs += static_cast<int32_t>((1.0e6 * bufSizeSamples) / + _inStreamFormat.mChannelsPerFrame / + _inStreamFormat.mSampleRate + + 0.5); - data->mBuffers->mNumberChannels = _inStreamFormat.mChannelsPerFrame; - *numberDataPackets = numSamples / _inStreamFormat.mChannelsPerFrame; - data->mBuffers->mDataByteSize = *numberDataPackets - * _inStreamFormat.mBytesPerPacket; + AtomicSet32(&_captureDelayUs, captureDelayUs); - return 0; + RTC_DCHECK(inputData->mNumberBuffers == 1); + PaRingBufferSize numSamples = inputData->mBuffers->mDataByteSize * + _inStreamFormat.mChannelsPerFrame / + _inStreamFormat.mBytesPerPacket; + PaUtil_WriteRingBuffer(_paCaptureBuffer, inputData->mBuffers->mData, + numSamples); + + kern_return_t kernErr = semaphore_signal_all(_captureSemaphore); + if (kernErr != KERN_SUCCESS) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " semaphore_signal_all() error: %d", kernErr); + } + + return err; } -bool AudioDeviceMac::RunRender(void* ptrThis) -{ - return static_cast<AudioDeviceMac*> (ptrThis)->RenderWorkerThread(); -} - -bool AudioDeviceMac::RenderWorkerThread() -{ - PaRingBufferSize numSamples = ENGINE_PLAY_BUF_SIZE_IN_SAMPLES - * _outDesiredFormat.mChannelsPerFrame; - while (PaUtil_GetRingBufferWriteAvailable(_paRenderBuffer) - - _renderDelayOffsetSamples < numSamples) - { - mach_timespec_t timeout; - timeout.tv_sec = 0; - timeout.tv_nsec = TIMER_PERIOD_MS; - - kern_return_t kernErr = semaphore_timedwait(_renderSemaphore, timeout); - if (kernErr == KERN_OPERATION_TIMED_OUT) - { - int32_t signal = AtomicGet32(&_renderDeviceIsAlive); - if (signal == 0) - { - // The render device is no longer alive; stop the worker thread. - return false; - } - } else if (kernErr != KERN_SUCCESS) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " semaphore_timedwait() error: %d", kernErr); - } +OSStatus AudioDeviceMac::implInConverterProc(UInt32* numberDataPackets, + AudioBufferList* data) { + RTC_DCHECK(data->mNumberBuffers == 1); + PaRingBufferSize numSamples = + *numberDataPackets * _inStreamFormat.mChannelsPerFrame; + + while (PaUtil_GetRingBufferReadAvailable(_paCaptureBuffer) < numSamples) { + mach_timespec_t timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = TIMER_PERIOD_MS; + + kern_return_t kernErr = semaphore_timedwait(_captureSemaphore, timeout); + if (kernErr == KERN_OPERATION_TIMED_OUT) { + int32_t signal = AtomicGet32(&_captureDeviceIsAlive); + if (signal == 0) { + // The capture device is no longer alive; stop the worker thread. + *numberDataPackets = 0; + return 1; + } + } else if (kernErr != KERN_SUCCESS) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " semaphore_wait() error: %d", kernErr); } + } - int8_t playBuffer[4 * ENGINE_PLAY_BUF_SIZE_IN_SAMPLES]; - - if (!_ptrAudioBuffer) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " capture AudioBuffer is invalid"); + // Pass the read pointer directly to the converter to avoid a memcpy. + void* dummyPtr; + PaRingBufferSize dummySize; + PaUtil_GetRingBufferReadRegions(_paCaptureBuffer, numSamples, + &data->mBuffers->mData, &numSamples, + &dummyPtr, &dummySize); + PaUtil_AdvanceRingBufferReadIndex(_paCaptureBuffer, numSamples); + + data->mBuffers->mNumberChannels = _inStreamFormat.mChannelsPerFrame; + *numberDataPackets = numSamples / _inStreamFormat.mChannelsPerFrame; + data->mBuffers->mDataByteSize = + *numberDataPackets * _inStreamFormat.mBytesPerPacket; + + return 0; +} + +bool AudioDeviceMac::RunRender(void* ptrThis) { + return static_cast<AudioDeviceMac*>(ptrThis)->RenderWorkerThread(); +} + +bool AudioDeviceMac::RenderWorkerThread() { + PaRingBufferSize numSamples = + ENGINE_PLAY_BUF_SIZE_IN_SAMPLES * _outDesiredFormat.mChannelsPerFrame; + while (PaUtil_GetRingBufferWriteAvailable(_paRenderBuffer) - + _renderDelayOffsetSamples < + numSamples) { + mach_timespec_t timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = TIMER_PERIOD_MS; + + kern_return_t kernErr = semaphore_timedwait(_renderSemaphore, timeout); + if (kernErr == KERN_OPERATION_TIMED_OUT) { + int32_t signal = AtomicGet32(&_renderDeviceIsAlive); + if (signal == 0) { + // The render device is no longer alive; stop the worker thread. return false; + } + } else if (kernErr != KERN_SUCCESS) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " semaphore_timedwait() error: %d", kernErr); } + } - // Ask for new PCM data to be played out using the AudioDeviceBuffer. - uint32_t nSamples = - _ptrAudioBuffer->RequestPlayoutData(ENGINE_PLAY_BUF_SIZE_IN_SAMPLES); + int8_t playBuffer[4 * ENGINE_PLAY_BUF_SIZE_IN_SAMPLES]; - nSamples = _ptrAudioBuffer->GetPlayoutData(playBuffer); - if (nSamples != ENGINE_PLAY_BUF_SIZE_IN_SAMPLES) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " invalid number of output samples(%d)", nSamples); - } + if (!_ptrAudioBuffer) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " capture AudioBuffer is invalid"); + return false; + } - uint32_t nOutSamples = nSamples * _outDesiredFormat.mChannelsPerFrame; - - SInt16 *pPlayBuffer = (SInt16 *) &playBuffer; - if (_macBookProPanRight && (_playChannels == 2)) - { - // Mix entirely into the right channel and zero the left channel. - SInt32 sampleInt32 = 0; - for (uint32_t sampleIdx = 0; sampleIdx < nOutSamples; sampleIdx - += 2) - { - sampleInt32 = pPlayBuffer[sampleIdx]; - sampleInt32 += pPlayBuffer[sampleIdx + 1]; - sampleInt32 /= 2; - - if (sampleInt32 > 32767) - { - sampleInt32 = 32767; - } else if (sampleInt32 < -32768) - { - sampleInt32 = -32768; - } - - pPlayBuffer[sampleIdx] = 0; - pPlayBuffer[sampleIdx + 1] = static_cast<SInt16> (sampleInt32); - } + // Ask for new PCM data to be played out using the AudioDeviceBuffer. + uint32_t nSamples = + _ptrAudioBuffer->RequestPlayoutData(ENGINE_PLAY_BUF_SIZE_IN_SAMPLES); + + nSamples = _ptrAudioBuffer->GetPlayoutData(playBuffer); + if (nSamples != ENGINE_PLAY_BUF_SIZE_IN_SAMPLES) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " invalid number of output samples(%d)", nSamples); + } + + uint32_t nOutSamples = nSamples * _outDesiredFormat.mChannelsPerFrame; + + SInt16* pPlayBuffer = (SInt16*)&playBuffer; + if (_macBookProPanRight && (_playChannels == 2)) { + // Mix entirely into the right channel and zero the left channel. + SInt32 sampleInt32 = 0; + for (uint32_t sampleIdx = 0; sampleIdx < nOutSamples; sampleIdx += 2) { + sampleInt32 = pPlayBuffer[sampleIdx]; + sampleInt32 += pPlayBuffer[sampleIdx + 1]; + sampleInt32 /= 2; + + if (sampleInt32 > 32767) { + sampleInt32 = 32767; + } else if (sampleInt32 < -32768) { + sampleInt32 = -32768; + } + + pPlayBuffer[sampleIdx] = 0; + pPlayBuffer[sampleIdx + 1] = static_cast<SInt16>(sampleInt32); } + } - PaUtil_WriteRingBuffer(_paRenderBuffer, pPlayBuffer, nOutSamples); + PaUtil_WriteRingBuffer(_paRenderBuffer, pPlayBuffer, nOutSamples); - return true; + return true; } -bool AudioDeviceMac::RunCapture(void* ptrThis) -{ - return static_cast<AudioDeviceMac*> (ptrThis)->CaptureWorkerThread(); +bool AudioDeviceMac::RunCapture(void* ptrThis) { + return static_cast<AudioDeviceMac*>(ptrThis)->CaptureWorkerThread(); } -bool AudioDeviceMac::CaptureWorkerThread() -{ - OSStatus err = noErr; - UInt32 noRecSamples = ENGINE_REC_BUF_SIZE_IN_SAMPLES - * _inDesiredFormat.mChannelsPerFrame; - SInt16 recordBuffer[noRecSamples]; - UInt32 size = ENGINE_REC_BUF_SIZE_IN_SAMPLES; - - AudioBufferList engineBuffer; - engineBuffer.mNumberBuffers = 1; // Interleaved channels. - engineBuffer.mBuffers->mNumberChannels = _inDesiredFormat.mChannelsPerFrame; - engineBuffer.mBuffers->mDataByteSize = _inDesiredFormat.mBytesPerPacket - * noRecSamples; - engineBuffer.mBuffers->mData = recordBuffer; - - err = AudioConverterFillComplexBuffer(_captureConverter, inConverterProc, - this, &size, &engineBuffer, NULL); - if (err != noErr) - { - if (err == 1) - { - // This is our own error. - return false; - } else - { - logCAMsg(kTraceError, kTraceAudioDevice, _id, - "Error in AudioConverterFillComplexBuffer()", - (const char *) &err); - return false; - } +bool AudioDeviceMac::CaptureWorkerThread() { + OSStatus err = noErr; + UInt32 noRecSamples = + ENGINE_REC_BUF_SIZE_IN_SAMPLES * _inDesiredFormat.mChannelsPerFrame; + SInt16 recordBuffer[noRecSamples]; + UInt32 size = ENGINE_REC_BUF_SIZE_IN_SAMPLES; + + AudioBufferList engineBuffer; + engineBuffer.mNumberBuffers = 1; // Interleaved channels. + engineBuffer.mBuffers->mNumberChannels = _inDesiredFormat.mChannelsPerFrame; + engineBuffer.mBuffers->mDataByteSize = + _inDesiredFormat.mBytesPerPacket * noRecSamples; + engineBuffer.mBuffers->mData = recordBuffer; + + err = AudioConverterFillComplexBuffer(_captureConverter, inConverterProc, + this, &size, &engineBuffer, NULL); + if (err != noErr) { + if (err == 1) { + // This is our own error. + return false; + } else { + logCAMsg(kTraceError, kTraceAudioDevice, _id, + "Error in AudioConverterFillComplexBuffer()", (const char*)&err); + return false; } + } - // TODO(xians): what if the returned size is incorrect? - if (size == ENGINE_REC_BUF_SIZE_IN_SAMPLES) - { - uint32_t currentMicLevel(0); - uint32_t newMicLevel(0); - int32_t msecOnPlaySide; - int32_t msecOnRecordSide; - - int32_t captureDelayUs = AtomicGet32(&_captureDelayUs); - int32_t renderDelayUs = AtomicGet32(&_renderDelayUs); - - msecOnPlaySide = static_cast<int32_t> (1e-3 * (renderDelayUs + - _renderLatencyUs) + 0.5); - msecOnRecordSide = static_cast<int32_t> (1e-3 * (captureDelayUs + - _captureLatencyUs) + - 0.5); - - if (!_ptrAudioBuffer) - { - WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, - " capture AudioBuffer is invalid"); - return false; - } + // TODO(xians): what if the returned size is incorrect? + if (size == ENGINE_REC_BUF_SIZE_IN_SAMPLES) { + uint32_t currentMicLevel(0); + uint32_t newMicLevel(0); + int32_t msecOnPlaySide; + int32_t msecOnRecordSide; - // store the recorded buffer (no action will be taken if the - // #recorded samples is not a full buffer) - _ptrAudioBuffer->SetRecordedBuffer((int8_t*) &recordBuffer, - (uint32_t) size); - - if (AGC()) - { - // Use mod to ensure we check the volume on the first pass. - if (get_mic_volume_counter_ms_ % kGetMicVolumeIntervalMs == 0) { - get_mic_volume_counter_ms_ = 0; - // store current mic level in the audio buffer if AGC is enabled - if (MicrophoneVolume(currentMicLevel) == 0) - { - // this call does not affect the actual microphone volume - _ptrAudioBuffer->SetCurrentMicLevel(currentMicLevel); - } - } - get_mic_volume_counter_ms_ += kBufferSizeMs; - } + int32_t captureDelayUs = AtomicGet32(&_captureDelayUs); + int32_t renderDelayUs = AtomicGet32(&_renderDelayUs); - _ptrAudioBuffer->SetVQEData(msecOnPlaySide, msecOnRecordSide, 0); - - _ptrAudioBuffer->SetTypingStatus(KeyPressed()); - - // deliver recorded samples at specified sample rate, mic level etc. - // to the observer using callback - _ptrAudioBuffer->DeliverRecordedData(); - - if (AGC()) - { - newMicLevel = _ptrAudioBuffer->NewMicLevel(); - if (newMicLevel != 0) - { - // The VQE will only deliver non-zero microphone levels when - // a change is needed. - // Set this new mic level (received from the observer as return - // value in the callback). - WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, - _id, " AGC change of volume: old=%u => new=%u", - currentMicLevel, newMicLevel); - if (SetMicrophoneVolume(newMicLevel) == -1) - { - WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, - " the required modification of the microphone " - "volume failed"); - } - } + msecOnPlaySide = + static_cast<int32_t>(1e-3 * (renderDelayUs + _renderLatencyUs) + 0.5); + msecOnRecordSide = + static_cast<int32_t>(1e-3 * (captureDelayUs + _captureLatencyUs) + 0.5); + + if (!_ptrAudioBuffer) { + WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, + " capture AudioBuffer is invalid"); + return false; + } + + // store the recorded buffer (no action will be taken if the + // #recorded samples is not a full buffer) + _ptrAudioBuffer->SetRecordedBuffer((int8_t*)&recordBuffer, (uint32_t)size); + + if (AGC()) { + // Use mod to ensure we check the volume on the first pass. + if (get_mic_volume_counter_ms_ % kGetMicVolumeIntervalMs == 0) { + get_mic_volume_counter_ms_ = 0; + // store current mic level in the audio buffer if AGC is enabled + if (MicrophoneVolume(currentMicLevel) == 0) { + // this call does not affect the actual microphone volume + _ptrAudioBuffer->SetCurrentMicLevel(currentMicLevel); } + } + get_mic_volume_counter_ms_ += kBufferSizeMs; + } + + _ptrAudioBuffer->SetVQEData(msecOnPlaySide, msecOnRecordSide, 0); + + _ptrAudioBuffer->SetTypingStatus(KeyPressed()); + + // deliver recorded samples at specified sample rate, mic level etc. + // to the observer using callback + _ptrAudioBuffer->DeliverRecordedData(); + + if (AGC()) { + newMicLevel = _ptrAudioBuffer->NewMicLevel(); + if (newMicLevel != 0) { + // The VQE will only deliver non-zero microphone levels when + // a change is needed. + // Set this new mic level (received from the observer as return + // value in the callback). + WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id, + " AGC change of volume: old=%u => new=%u", + currentMicLevel, newMicLevel); + if (SetMicrophoneVolume(newMicLevel) == -1) { + WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, + " the required modification of the microphone " + "volume failed"); + } + } } + } - return true; + return true; } bool AudioDeviceMac::KeyPressed() { bool key_down = false; // Loop through all Mac virtual key constant values. - for (unsigned int key_index = 0; - key_index < arraysize(prev_key_state_); - ++key_index) { - bool keyState = CGEventSourceKeyState( - kCGEventSourceStateHIDSystemState, - key_index); + for (unsigned int key_index = 0; key_index < arraysize(prev_key_state_); + ++key_index) { + bool keyState = + CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, key_index); // A false -> true change in keymap means a key is pressed. key_down |= (keyState && !prev_key_state_[key_index]); // Save current state. diff --git a/webrtc/modules/audio_device/mac/audio_device_mac.h b/webrtc/modules/audio_device/mac/audio_device_mac.h index 849e74ce45..ca3a51997d 100644 --- a/webrtc/modules/audio_device/mac/audio_device_mac.h +++ b/webrtc/modules/audio_device/mac/audio_device_mac.h @@ -27,15 +27,14 @@ namespace rtc { class PlatformThread; } // namespace rtc -namespace webrtc -{ +namespace webrtc { class EventWrapper; const uint32_t N_REC_SAMPLES_PER_SEC = 48000; const uint32_t N_PLAY_SAMPLES_PER_SEC = 48000; -const uint32_t N_REC_CHANNELS = 1; // default is mono recording -const uint32_t N_PLAY_CHANNELS = 2; // default is stereo playout +const uint32_t N_REC_CHANNELS = 1; // default is mono recording +const uint32_t N_PLAY_CHANNELS = 2; // default is stereo playout const uint32_t N_DEVICE_CHANNELS = 64; const int kBufferSizeMs = 10; @@ -46,7 +45,7 @@ const uint32_t ENGINE_PLAY_BUF_SIZE_IN_SAMPLES = N_PLAY_SAMPLES_PER_SEC * kBufferSizeMs / 1000; const int N_BLOCKS_IO = 2; -const int N_BUFFERS_IN = 2; // Must be at least N_BLOCKS_IO. +const int N_BUFFERS_IN = 2; // Must be at least N_BLOCKS_IO. const int N_BUFFERS_OUT = 3; // Must be at least N_BLOCKS_IO. const uint32_t TIMER_PERIOD_MS = 2 * 10 * N_BLOCKS_IO * 1000000; @@ -58,328 +57,325 @@ const uint32_t PLAY_BUF_SIZE_IN_SAMPLES = const int kGetMicVolumeIntervalMs = 1000; -class AudioDeviceMac: public AudioDeviceGeneric -{ -public: - AudioDeviceMac(const int32_t id); - ~AudioDeviceMac(); - - // Retrieve the currently utilized audio layer - virtual int32_t - ActiveAudioLayer(AudioDeviceModule::AudioLayer& audioLayer) const; - - // Main initializaton and termination - virtual int32_t Init(); - virtual int32_t Terminate(); - virtual bool Initialized() const; - - // Device enumeration - virtual int16_t PlayoutDevices(); - virtual int16_t RecordingDevices(); - virtual int32_t PlayoutDeviceName( - uint16_t index, - char name[kAdmMaxDeviceNameSize], - char guid[kAdmMaxGuidSize]); - virtual int32_t RecordingDeviceName( - uint16_t index, - char name[kAdmMaxDeviceNameSize], - char guid[kAdmMaxGuidSize]); - - // Device selection - virtual int32_t SetPlayoutDevice(uint16_t index); - virtual int32_t SetPlayoutDevice( - AudioDeviceModule::WindowsDeviceType device); - virtual int32_t SetRecordingDevice(uint16_t index); - virtual int32_t SetRecordingDevice( - AudioDeviceModule::WindowsDeviceType device); - - // Audio transport initialization - virtual int32_t PlayoutIsAvailable(bool& available); - virtual int32_t InitPlayout(); - virtual bool PlayoutIsInitialized() const; - virtual int32_t RecordingIsAvailable(bool& available); - virtual int32_t InitRecording(); - virtual bool RecordingIsInitialized() const; - - // Audio transport control - virtual int32_t StartPlayout(); - virtual int32_t StopPlayout(); - virtual bool Playing() const; - virtual int32_t StartRecording(); - virtual int32_t StopRecording(); - virtual bool Recording() const; - - // Microphone Automatic Gain Control (AGC) - virtual int32_t SetAGC(bool enable); - virtual bool AGC() const; - - // Volume control based on the Windows Wave API (Windows only) - virtual int32_t SetWaveOutVolume(uint16_t volumeLeft, uint16_t volumeRight); - virtual int32_t WaveOutVolume(uint16_t& volumeLeft, - uint16_t& volumeRight) const; - - // Audio mixer initialization - virtual int32_t InitSpeaker(); - virtual bool SpeakerIsInitialized() const; - virtual int32_t InitMicrophone(); - virtual bool MicrophoneIsInitialized() const; - - // Speaker volume controls - virtual int32_t SpeakerVolumeIsAvailable(bool& available); - virtual int32_t SetSpeakerVolume(uint32_t volume); - virtual int32_t SpeakerVolume(uint32_t& volume) const; - virtual int32_t MaxSpeakerVolume(uint32_t& maxVolume) const; - virtual int32_t MinSpeakerVolume(uint32_t& minVolume) const; - virtual int32_t SpeakerVolumeStepSize(uint16_t& stepSize) const; - - // Microphone volume controls - virtual int32_t MicrophoneVolumeIsAvailable(bool& available); - virtual int32_t SetMicrophoneVolume(uint32_t volume); - virtual int32_t MicrophoneVolume(uint32_t& volume) const; - virtual int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const; - virtual int32_t MinMicrophoneVolume(uint32_t& minVolume) const; - virtual int32_t - MicrophoneVolumeStepSize(uint16_t& stepSize) const; - - // Microphone mute control - virtual int32_t MicrophoneMuteIsAvailable(bool& available); - virtual int32_t SetMicrophoneMute(bool enable); - virtual int32_t MicrophoneMute(bool& enabled) const; - - // Speaker mute control - virtual int32_t SpeakerMuteIsAvailable(bool& available); - virtual int32_t SetSpeakerMute(bool enable); - virtual int32_t SpeakerMute(bool& enabled) const; - - // Microphone boost control - virtual int32_t MicrophoneBoostIsAvailable(bool& available); - virtual int32_t SetMicrophoneBoost(bool enable); - virtual int32_t MicrophoneBoost(bool& enabled) const; - - // Stereo support - virtual int32_t StereoPlayoutIsAvailable(bool& available); - virtual int32_t SetStereoPlayout(bool enable); - virtual int32_t StereoPlayout(bool& enabled) const; - virtual int32_t StereoRecordingIsAvailable(bool& available); - virtual int32_t SetStereoRecording(bool enable); - virtual int32_t StereoRecording(bool& enabled) const; - - // Delay information and control - virtual int32_t - SetPlayoutBuffer(const AudioDeviceModule::BufferType type, - uint16_t sizeMS); - virtual int32_t PlayoutBuffer(AudioDeviceModule::BufferType& type, - uint16_t& sizeMS) const; - virtual int32_t PlayoutDelay(uint16_t& delayMS) const; - virtual int32_t RecordingDelay(uint16_t& delayMS) const; - - // CPU load - virtual int32_t CPULoad(uint16_t& load) const; - - virtual bool PlayoutWarning() const; - virtual bool PlayoutError() const; - virtual bool RecordingWarning() const; - virtual bool RecordingError() const; - virtual void ClearPlayoutWarning(); - virtual void ClearPlayoutError(); - virtual void ClearRecordingWarning(); - virtual void ClearRecordingError(); - - virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer); - -private: - virtual int32_t MicrophoneIsAvailable(bool& available); - virtual int32_t SpeakerIsAvailable(bool& available); - - static void AtomicSet32(int32_t* theValue, int32_t newValue); - static int32_t AtomicGet32(int32_t* theValue); - - static void logCAMsg(const TraceLevel level, - const TraceModule module, - const int32_t id, const char *msg, - const char *err); - - int32_t GetNumberDevices(const AudioObjectPropertyScope scope, - AudioDeviceID scopedDeviceIds[], - const uint32_t deviceListLength); - - int32_t GetDeviceName(const AudioObjectPropertyScope scope, - const uint16_t index, char* name); - - int32_t InitDevice(uint16_t userDeviceIndex, - AudioDeviceID& deviceId, bool isInput); - - // Always work with our preferred playout format inside VoE. - // Then convert the output to the OS setting using an AudioConverter. - OSStatus SetDesiredPlayoutFormat(); - - static OSStatus - objectListenerProc(AudioObjectID objectId, UInt32 numberAddresses, - const AudioObjectPropertyAddress addresses[], - void* clientData); - - OSStatus - implObjectListenerProc(AudioObjectID objectId, UInt32 numberAddresses, - const AudioObjectPropertyAddress addresses[]); - - int32_t HandleDeviceChange(); - - int32_t - HandleStreamFormatChange(AudioObjectID objectId, +class AudioDeviceMac : public AudioDeviceGeneric { + public: + AudioDeviceMac(const int32_t id); + ~AudioDeviceMac(); + + // Retrieve the currently utilized audio layer + virtual int32_t ActiveAudioLayer( + AudioDeviceModule::AudioLayer& audioLayer) const; + + // Main initializaton and termination + virtual int32_t Init(); + virtual int32_t Terminate(); + virtual bool Initialized() const; + + // Device enumeration + virtual int16_t PlayoutDevices(); + virtual int16_t RecordingDevices(); + virtual int32_t PlayoutDeviceName(uint16_t index, + char name[kAdmMaxDeviceNameSize], + char guid[kAdmMaxGuidSize]); + virtual int32_t RecordingDeviceName(uint16_t index, + char name[kAdmMaxDeviceNameSize], + char guid[kAdmMaxGuidSize]); + + // Device selection + virtual int32_t SetPlayoutDevice(uint16_t index); + virtual int32_t SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType device); + virtual int32_t SetRecordingDevice(uint16_t index); + virtual int32_t SetRecordingDevice( + AudioDeviceModule::WindowsDeviceType device); + + // Audio transport initialization + virtual int32_t PlayoutIsAvailable(bool& available); + virtual int32_t InitPlayout(); + virtual bool PlayoutIsInitialized() const; + virtual int32_t RecordingIsAvailable(bool& available); + virtual int32_t InitRecording(); + virtual bool RecordingIsInitialized() const; + + // Audio transport control + virtual int32_t StartPlayout(); + virtual int32_t StopPlayout(); + virtual bool Playing() const; + virtual int32_t StartRecording(); + virtual int32_t StopRecording(); + virtual bool Recording() const; + + // Microphone Automatic Gain Control (AGC) + virtual int32_t SetAGC(bool enable); + virtual bool AGC() const; + + // Volume control based on the Windows Wave API (Windows only) + virtual int32_t SetWaveOutVolume(uint16_t volumeLeft, uint16_t volumeRight); + virtual int32_t WaveOutVolume(uint16_t& volumeLeft, + uint16_t& volumeRight) const; + + // Audio mixer initialization + virtual int32_t InitSpeaker(); + virtual bool SpeakerIsInitialized() const; + virtual int32_t InitMicrophone(); + virtual bool MicrophoneIsInitialized() const; + + // Speaker volume controls + virtual int32_t SpeakerVolumeIsAvailable(bool& available); + virtual int32_t SetSpeakerVolume(uint32_t volume); + virtual int32_t SpeakerVolume(uint32_t& volume) const; + virtual int32_t MaxSpeakerVolume(uint32_t& maxVolume) const; + virtual int32_t MinSpeakerVolume(uint32_t& minVolume) const; + virtual int32_t SpeakerVolumeStepSize(uint16_t& stepSize) const; + + // Microphone volume controls + virtual int32_t MicrophoneVolumeIsAvailable(bool& available); + virtual int32_t SetMicrophoneVolume(uint32_t volume); + virtual int32_t MicrophoneVolume(uint32_t& volume) const; + virtual int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const; + virtual int32_t MinMicrophoneVolume(uint32_t& minVolume) const; + virtual int32_t MicrophoneVolumeStepSize(uint16_t& stepSize) const; + + // Microphone mute control + virtual int32_t MicrophoneMuteIsAvailable(bool& available); + virtual int32_t SetMicrophoneMute(bool enable); + virtual int32_t MicrophoneMute(bool& enabled) const; + + // Speaker mute control + virtual int32_t SpeakerMuteIsAvailable(bool& available); + virtual int32_t SetSpeakerMute(bool enable); + virtual int32_t SpeakerMute(bool& enabled) const; + + // Microphone boost control + virtual int32_t MicrophoneBoostIsAvailable(bool& available); + virtual int32_t SetMicrophoneBoost(bool enable); + virtual int32_t MicrophoneBoost(bool& enabled) const; + + // Stereo support + virtual int32_t StereoPlayoutIsAvailable(bool& available); + virtual int32_t SetStereoPlayout(bool enable); + virtual int32_t StereoPlayout(bool& enabled) const; + virtual int32_t StereoRecordingIsAvailable(bool& available); + virtual int32_t SetStereoRecording(bool enable); + virtual int32_t StereoRecording(bool& enabled) const; + + // Delay information and control + virtual int32_t SetPlayoutBuffer(const AudioDeviceModule::BufferType type, + uint16_t sizeMS); + virtual int32_t PlayoutBuffer(AudioDeviceModule::BufferType& type, + uint16_t& sizeMS) const; + virtual int32_t PlayoutDelay(uint16_t& delayMS) const; + virtual int32_t RecordingDelay(uint16_t& delayMS) const; + + // CPU load + virtual int32_t CPULoad(uint16_t& load) const; + + virtual bool PlayoutWarning() const; + virtual bool PlayoutError() const; + virtual bool RecordingWarning() const; + virtual bool RecordingError() const; + virtual void ClearPlayoutWarning(); + virtual void ClearPlayoutError(); + virtual void ClearRecordingWarning(); + virtual void ClearRecordingError(); + + virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer); + + private: + virtual int32_t MicrophoneIsAvailable(bool& available); + virtual int32_t SpeakerIsAvailable(bool& available); + + static void AtomicSet32(int32_t* theValue, int32_t newValue); + static int32_t AtomicGet32(int32_t* theValue); + + static void logCAMsg(const TraceLevel level, + const TraceModule module, + const int32_t id, + const char* msg, + const char* err); + + int32_t GetNumberDevices(const AudioObjectPropertyScope scope, + AudioDeviceID scopedDeviceIds[], + const uint32_t deviceListLength); + + int32_t GetDeviceName(const AudioObjectPropertyScope scope, + const uint16_t index, + char* name); + + int32_t InitDevice(uint16_t userDeviceIndex, + AudioDeviceID& deviceId, + bool isInput); + + // Always work with our preferred playout format inside VoE. + // Then convert the output to the OS setting using an AudioConverter. + OSStatus SetDesiredPlayoutFormat(); + + static OSStatus objectListenerProc( + AudioObjectID objectId, + UInt32 numberAddresses, + const AudioObjectPropertyAddress addresses[], + void* clientData); + + OSStatus implObjectListenerProc(AudioObjectID objectId, + UInt32 numberAddresses, + const AudioObjectPropertyAddress addresses[]); + + int32_t HandleDeviceChange(); + + int32_t HandleStreamFormatChange(AudioObjectID objectId, + AudioObjectPropertyAddress propertyAddress); + + int32_t HandleDataSourceChange(AudioObjectID objectId, AudioObjectPropertyAddress propertyAddress); - int32_t - HandleDataSourceChange(AudioObjectID objectId, - AudioObjectPropertyAddress propertyAddress); - - int32_t - HandleProcessorOverload(AudioObjectPropertyAddress propertyAddress); - - static OSStatus deviceIOProc(AudioDeviceID device, - const AudioTimeStamp *now, - const AudioBufferList *inputData, - const AudioTimeStamp *inputTime, - AudioBufferList *outputData, + int32_t HandleProcessorOverload(AudioObjectPropertyAddress propertyAddress); + + static OSStatus deviceIOProc(AudioDeviceID device, + const AudioTimeStamp* now, + const AudioBufferList* inputData, + const AudioTimeStamp* inputTime, + AudioBufferList* outputData, + const AudioTimeStamp* outputTime, + void* clientData); + + static OSStatus outConverterProc( + AudioConverterRef audioConverter, + UInt32* numberDataPackets, + AudioBufferList* data, + AudioStreamPacketDescription** dataPacketDescription, + void* userData); + + static OSStatus inDeviceIOProc(AudioDeviceID device, + const AudioTimeStamp* now, + const AudioBufferList* inputData, + const AudioTimeStamp* inputTime, + AudioBufferList* outputData, const AudioTimeStamp* outputTime, - void *clientData); - - static OSStatus - outConverterProc(AudioConverterRef audioConverter, - UInt32 *numberDataPackets, AudioBufferList *data, - AudioStreamPacketDescription **dataPacketDescription, - void *userData); - - static OSStatus inDeviceIOProc(AudioDeviceID device, - const AudioTimeStamp *now, - const AudioBufferList *inputData, - const AudioTimeStamp *inputTime, - AudioBufferList *outputData, - const AudioTimeStamp *outputTime, - void *clientData); + void* clientData); - static OSStatus - inConverterProc(AudioConverterRef audioConverter, - UInt32 *numberDataPackets, AudioBufferList *data, - AudioStreamPacketDescription **dataPacketDescription, - void *inUserData); + static OSStatus inConverterProc( + AudioConverterRef audioConverter, + UInt32* numberDataPackets, + AudioBufferList* data, + AudioStreamPacketDescription** dataPacketDescription, + void* inUserData); - OSStatus implDeviceIOProc(const AudioBufferList *inputData, - const AudioTimeStamp *inputTime, - AudioBufferList *outputData, - const AudioTimeStamp *outputTime); + OSStatus implDeviceIOProc(const AudioBufferList* inputData, + const AudioTimeStamp* inputTime, + AudioBufferList* outputData, + const AudioTimeStamp* outputTime); - OSStatus implOutConverterProc(UInt32 *numberDataPackets, - AudioBufferList *data); + OSStatus implOutConverterProc(UInt32* numberDataPackets, + AudioBufferList* data); - OSStatus implInDeviceIOProc(const AudioBufferList *inputData, - const AudioTimeStamp *inputTime); + OSStatus implInDeviceIOProc(const AudioBufferList* inputData, + const AudioTimeStamp* inputTime); - OSStatus implInConverterProc(UInt32 *numberDataPackets, - AudioBufferList *data); + OSStatus implInConverterProc(UInt32* numberDataPackets, + AudioBufferList* data); - static bool RunCapture(void*); - static bool RunRender(void*); - bool CaptureWorkerThread(); - bool RenderWorkerThread(); + static bool RunCapture(void*); + static bool RunRender(void*); + bool CaptureWorkerThread(); + bool RenderWorkerThread(); - bool KeyPressed(); + bool KeyPressed(); - AudioDeviceBuffer* _ptrAudioBuffer; + AudioDeviceBuffer* _ptrAudioBuffer; - CriticalSectionWrapper& _critSect; + CriticalSectionWrapper& _critSect; - EventWrapper& _stopEventRec; - EventWrapper& _stopEvent; + EventWrapper& _stopEventRec; + EventWrapper& _stopEvent; - // TODO(pbos): Replace with direct members, just start/stop, no need to - // recreate the thread. - // Only valid/running between calls to StartRecording and StopRecording. - rtc::scoped_ptr<rtc::PlatformThread> capture_worker_thread_; + // TODO(pbos): Replace with direct members, just start/stop, no need to + // recreate the thread. + // Only valid/running between calls to StartRecording and StopRecording. + rtc::scoped_ptr<rtc::PlatformThread> capture_worker_thread_; - // Only valid/running between calls to StartPlayout and StopPlayout. - rtc::scoped_ptr<rtc::PlatformThread> render_worker_thread_; + // Only valid/running between calls to StartPlayout and StopPlayout. + rtc::scoped_ptr<rtc::PlatformThread> render_worker_thread_; - int32_t _id; + int32_t _id; - AudioMixerManagerMac _mixerManager; + AudioMixerManagerMac _mixerManager; - uint16_t _inputDeviceIndex; - uint16_t _outputDeviceIndex; - AudioDeviceID _inputDeviceID; - AudioDeviceID _outputDeviceID; + uint16_t _inputDeviceIndex; + uint16_t _outputDeviceIndex; + AudioDeviceID _inputDeviceID; + AudioDeviceID _outputDeviceID; #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - AudioDeviceIOProcID _inDeviceIOProcID; - AudioDeviceIOProcID _deviceIOProcID; + AudioDeviceIOProcID _inDeviceIOProcID; + AudioDeviceIOProcID _deviceIOProcID; #endif - bool _inputDeviceIsSpecified; - bool _outputDeviceIsSpecified; + bool _inputDeviceIsSpecified; + bool _outputDeviceIsSpecified; - uint8_t _recChannels; - uint8_t _playChannels; + uint8_t _recChannels; + uint8_t _playChannels; - Float32* _captureBufData; - SInt16* _renderBufData; + Float32* _captureBufData; + SInt16* _renderBufData; - SInt16 _renderConvertData[PLAY_BUF_SIZE_IN_SAMPLES]; + SInt16 _renderConvertData[PLAY_BUF_SIZE_IN_SAMPLES]; - AudioDeviceModule::BufferType _playBufType; + AudioDeviceModule::BufferType _playBufType; - bool _initialized; - bool _isShutDown; - bool _recording; - bool _playing; - bool _recIsInitialized; - bool _playIsInitialized; - bool _AGC; + bool _initialized; + bool _isShutDown; + bool _recording; + bool _playing; + bool _recIsInitialized; + bool _playIsInitialized; + bool _AGC; - // Atomically set varaibles - int32_t _renderDeviceIsAlive; - int32_t _captureDeviceIsAlive; + // Atomically set varaibles + int32_t _renderDeviceIsAlive; + int32_t _captureDeviceIsAlive; - bool _twoDevices; - bool _doStop; // For play if not shared device or play+rec if shared device - bool _doStopRec; // For rec if not shared device - bool _macBookPro; - bool _macBookProPanRight; + bool _twoDevices; + bool _doStop; // For play if not shared device or play+rec if shared device + bool _doStopRec; // For rec if not shared device + bool _macBookPro; + bool _macBookProPanRight; - AudioConverterRef _captureConverter; - AudioConverterRef _renderConverter; + AudioConverterRef _captureConverter; + AudioConverterRef _renderConverter; - AudioStreamBasicDescription _outStreamFormat; - AudioStreamBasicDescription _outDesiredFormat; - AudioStreamBasicDescription _inStreamFormat; - AudioStreamBasicDescription _inDesiredFormat; + AudioStreamBasicDescription _outStreamFormat; + AudioStreamBasicDescription _outDesiredFormat; + AudioStreamBasicDescription _inStreamFormat; + AudioStreamBasicDescription _inDesiredFormat; - uint32_t _captureLatencyUs; - uint32_t _renderLatencyUs; + uint32_t _captureLatencyUs; + uint32_t _renderLatencyUs; - // Atomically set variables - mutable int32_t _captureDelayUs; - mutable int32_t _renderDelayUs; + // Atomically set variables + mutable int32_t _captureDelayUs; + mutable int32_t _renderDelayUs; - int32_t _renderDelayOffsetSamples; + int32_t _renderDelayOffsetSamples; - uint16_t _playBufDelayFixed; // fixed playback delay + uint16_t _playBufDelayFixed; // fixed playback delay - uint16_t _playWarning; - uint16_t _playError; - uint16_t _recWarning; - uint16_t _recError; + uint16_t _playWarning; + uint16_t _playError; + uint16_t _recWarning; + uint16_t _recError; - PaUtilRingBuffer* _paCaptureBuffer; - PaUtilRingBuffer* _paRenderBuffer; + PaUtilRingBuffer* _paCaptureBuffer; + PaUtilRingBuffer* _paRenderBuffer; - semaphore_t _renderSemaphore; - semaphore_t _captureSemaphore; + semaphore_t _renderSemaphore; + semaphore_t _captureSemaphore; - int _captureBufSizeSamples; - int _renderBufSizeSamples; + int _captureBufSizeSamples; + int _renderBufSizeSamples; - // Typing detection - // 0x5c is key "9", after that comes function keys. - bool prev_key_state_[0x5d]; + // Typing detection + // 0x5c is key "9", after that comes function keys. + bool prev_key_state_[0x5d]; - int get_mic_volume_counter_ms_; + int get_mic_volume_counter_ms_; }; } // namespace webrtc 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 } diff --git a/webrtc/modules/audio_device/mac/audio_mixer_manager_mac.h b/webrtc/modules/audio_device/mac/audio_mixer_manager_mac.h index 94d6928921..9cbfe2deb4 100644 --- a/webrtc/modules/audio_device/mac/audio_mixer_manager_mac.h +++ b/webrtc/modules/audio_device/mac/audio_mixer_manager_mac.h @@ -18,63 +18,62 @@ #include <CoreAudio/CoreAudio.h> namespace webrtc { - -class AudioMixerManagerMac -{ -public: - int32_t OpenSpeaker(AudioDeviceID deviceID); - int32_t OpenMicrophone(AudioDeviceID deviceID); - int32_t SetSpeakerVolume(uint32_t volume); - int32_t SpeakerVolume(uint32_t& volume) const; - int32_t MaxSpeakerVolume(uint32_t& maxVolume) const; - int32_t MinSpeakerVolume(uint32_t& minVolume) const; - int32_t SpeakerVolumeStepSize(uint16_t& stepSize) const; - int32_t SpeakerVolumeIsAvailable(bool& available); - int32_t SpeakerMuteIsAvailable(bool& available); - int32_t SetSpeakerMute(bool enable); - int32_t SpeakerMute(bool& enabled) const; - int32_t StereoPlayoutIsAvailable(bool& available); - int32_t StereoRecordingIsAvailable(bool& available); - int32_t MicrophoneMuteIsAvailable(bool& available); - int32_t SetMicrophoneMute(bool enable); - int32_t MicrophoneMute(bool& enabled) const; - int32_t MicrophoneBoostIsAvailable(bool& available); - int32_t SetMicrophoneBoost(bool enable); - int32_t MicrophoneBoost(bool& enabled) const; - int32_t MicrophoneVolumeIsAvailable(bool& available); - int32_t SetMicrophoneVolume(uint32_t volume); - int32_t MicrophoneVolume(uint32_t& volume) const; - int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const; - int32_t MinMicrophoneVolume(uint32_t& minVolume) const; - int32_t MicrophoneVolumeStepSize(uint16_t& stepSize) const; - int32_t Close(); - int32_t CloseSpeaker(); - int32_t CloseMicrophone(); - bool SpeakerIsInitialized() const; - bool MicrophoneIsInitialized() const; -public: - AudioMixerManagerMac(const int32_t id); - ~AudioMixerManagerMac(); +class AudioMixerManagerMac { + public: + int32_t OpenSpeaker(AudioDeviceID deviceID); + int32_t OpenMicrophone(AudioDeviceID deviceID); + int32_t SetSpeakerVolume(uint32_t volume); + int32_t SpeakerVolume(uint32_t& volume) const; + int32_t MaxSpeakerVolume(uint32_t& maxVolume) const; + int32_t MinSpeakerVolume(uint32_t& minVolume) const; + int32_t SpeakerVolumeStepSize(uint16_t& stepSize) const; + int32_t SpeakerVolumeIsAvailable(bool& available); + int32_t SpeakerMuteIsAvailable(bool& available); + int32_t SetSpeakerMute(bool enable); + int32_t SpeakerMute(bool& enabled) const; + int32_t StereoPlayoutIsAvailable(bool& available); + int32_t StereoRecordingIsAvailable(bool& available); + int32_t MicrophoneMuteIsAvailable(bool& available); + int32_t SetMicrophoneMute(bool enable); + int32_t MicrophoneMute(bool& enabled) const; + int32_t MicrophoneBoostIsAvailable(bool& available); + int32_t SetMicrophoneBoost(bool enable); + int32_t MicrophoneBoost(bool& enabled) const; + int32_t MicrophoneVolumeIsAvailable(bool& available); + int32_t SetMicrophoneVolume(uint32_t volume); + int32_t MicrophoneVolume(uint32_t& volume) const; + int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const; + int32_t MinMicrophoneVolume(uint32_t& minVolume) const; + int32_t MicrophoneVolumeStepSize(uint16_t& stepSize) const; + int32_t Close(); + int32_t CloseSpeaker(); + int32_t CloseMicrophone(); + bool SpeakerIsInitialized() const; + bool MicrophoneIsInitialized() const; -private: - static void logCAMsg(const TraceLevel level, - const TraceModule module, - const int32_t id, const char *msg, - const char *err); + public: + AudioMixerManagerMac(const int32_t id); + ~AudioMixerManagerMac(); -private: - CriticalSectionWrapper& _critSect; - int32_t _id; + private: + static void logCAMsg(const TraceLevel level, + const TraceModule module, + const int32_t id, + const char* msg, + const char* err); - AudioDeviceID _inputDeviceID; - AudioDeviceID _outputDeviceID; + private: + CriticalSectionWrapper& _critSect; + int32_t _id; - uint16_t _noInputChannels; - uint16_t _noOutputChannels; + AudioDeviceID _inputDeviceID; + AudioDeviceID _outputDeviceID; + uint16_t _noInputChannels; + uint16_t _noOutputChannels; }; - + } // namespace webrtc #endif // AUDIO_MIXER_MAC_H |