Index: webrtc/modules/audio_device/mac/audio_device_mac.cc |
diff --git a/webrtc/modules/audio_device/mac/audio_device_mac.cc b/webrtc/modules/audio_device/mac/audio_device_mac.cc |
index d963f2b7f2a65503bce08ff238c7df4b0ef57609..0f33d1124deea786b1407133942e8b36bf978ae7 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) |
-{ |
- |
- CriticalSectionScoped lock(&_critSect); |
+void AudioDeviceMac::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) { |
+ 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() |
-{ |
+int32_t AudioDeviceMac::InitSpeaker() { |
+ CriticalSectionScoped lock(&_critSect); |
- 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) |
-{ |
+int32_t AudioDeviceMac::MicrophoneIsAvailable(bool& available) { |
+ bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); |
- 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) |
-{ |
+int32_t AudioDeviceMac::SpeakerVolumeIsAvailable(bool& available) { |
+ bool wasInitialized = _mixerManager.SpeakerIsInitialized(); |
- 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 |
-{ |
- |
- uint32_t maxVol(0); |
+int32_t AudioDeviceMac::MaxSpeakerVolume(uint32_t& maxVolume) const { |
+ 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) |
-{ |
+int32_t AudioDeviceMac::SpeakerMuteIsAvailable(bool& available) { |
+ bool isAvailable(false); |
+ bool wasInitialized = _mixerManager.SpeakerIsInitialized(); |
- 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) |
-{ |
- |
- bool isAvailable(false); |
- bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); |
+int32_t AudioDeviceMac::MicrophoneMuteIsAvailable(bool& available) { |
+ 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) |
-{ |
+int32_t AudioDeviceMac::MicrophoneBoostIsAvailable(bool& available) { |
+ bool isAvailable(false); |
+ bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); |
- 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 |
-{ |
- |
- if (_recChannels == 2) |
- enabled = true; |
- else |
- enabled = false; |
+int32_t AudioDeviceMac::SetStereoRecording(bool enable) { |
+ if (enable) |
+ _recChannels = 2; |
+ else |
+ _recChannels = 1; |
- 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 |
-{ |
+int32_t AudioDeviceMac::MaxMicrophoneVolume(uint32_t& maxVolume) const { |
+ uint32_t maxVol(0); |
- 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 |
-{ |
+int32_t AudioDeviceMac::MinMicrophoneVolume(uint32_t& minVolume) const { |
+ uint32_t minVol(0); |
- 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]) |
-{ |
- |
- const uint16_t nDevices(PlayoutDevices()); |
+int32_t AudioDeviceMac::PlayoutDeviceName(uint16_t index, |
+ char name[kAdmMaxDeviceNameSize], |
+ char guid[kAdmMaxGuidSize]) { |
+ 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]) |
-{ |
+int32_t AudioDeviceMac::RecordingDeviceName(uint16_t index, |
+ char name[kAdmMaxDeviceNameSize], |
+ char guid[kAdmMaxGuidSize]) { |
+ const uint16_t nDevices(RecordingDevices()); |
- 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) |
-{ |
+int32_t AudioDeviceMac::PlayoutIsAvailable(bool& available) { |
+ available = true; |
- 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) |
-{ |
+int32_t AudioDeviceMac::RecordingIsAvailable(bool& available) { |
+ available = true; |
- 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; |
+ } |
- _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; |
+ 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.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger |
- | kLinearPCMFormatFlagIsPacked; |
+ _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; |
#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); |
- |
- if (!_recIsInitialized) |
- { |
- return 0; |
- } |
+int32_t AudioDeviceMac::StopRecording() { |
+ CriticalSectionScoped lock(&_critSect); |
- 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); |
+ |
+ if (!_playIsInitialized) { |
+ return 0; |
+ } |
- CriticalSectionScoped lock(&_critSect); |
+ OSStatus err = noErr; |
- if (!_playIsInitialized) |
- { |
- return 0; |
+ 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++; |
+ } |
+ |
+ free(bufferList); |
+ bufferList = NULL; |
+ } // for |
+ } |
- return -1; |
+ 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; |
+ } |
+ } |
+ |
+ AudioObjectPropertyAddress propertyAddress = {kAudioDevicePropertyDeviceName, |
+ scope, 0}; |
+ |
+ if (isDefaultDevice) { |
+ char devName[len]; |
- WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(usedID, |
- &propertyAddress, 0, NULL, &len, name)); |
+ 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"); |
- |
- 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; |
- } |
+ WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, "Stream format changed"); |
- 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. |