1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/* 2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Use of this source code is governed by a BSD-style license 5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * that can be found in the LICENSE file in the root of the source 6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * tree. An additional intellectual property rights grant can be found 7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * in the file PATENTS. All contributing project authors may 8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * be found in the AUTHORS file in the root of the source tree. 9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 11bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/modules/audio_device/audio_device_config.h" 12bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/modules/audio_device/audio_device_utility.h" 13bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/modules/audio_device/mac/audio_device_mac.h" 14bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org 15bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/modules/audio_device/mac/portaudio/pa_ringbuffer.h" 16bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/system_wrappers/interface/event_wrapper.h" 17bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/system_wrappers/interface/thread_wrapper.h" 18bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/system_wrappers/interface/trace.h" 19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2028832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org#include <ApplicationServices/ApplicationServices.h> 213f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <assert.h> 22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <libkern/OSAtomic.h> // OSAtomicCompareAndSwap() 2328832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org#include <mach/mach.h> // mach_task_self() 2428832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org#include <sys/sysctl.h> // sysctlbyname() 2528832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org 2628832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org 27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc 29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define WEBRTC_CA_RETURN_ON_ERR(expr) \ 32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org do { \ 33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org err = expr; \ 34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err != noErr) { \ 35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, \ 36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Error in " #expr, (const char *)&err); \ 37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; \ 38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } \ 39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } while(0) 40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define WEBRTC_CA_LOG_ERR(expr) \ 42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org do { \ 43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org err = expr; \ 44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err != noErr) { \ 45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, \ 46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Error in " #expr, (const char *)&err); \ 47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } \ 48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } while(0) 49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define WEBRTC_CA_LOG_WARN(expr) \ 51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org do { \ 52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org err = expr; \ 53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err != noErr) { \ 54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceWarning, kTraceAudioDevice, _id, \ 55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Error in " #expr, (const char *)&err); \ 56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } \ 57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } while(0) 58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 59e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) 60e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org 61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgenum 62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org MaxNumberDevices = 64 64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}; 65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceMac::AtomicSet32(int32_t* theValue, int32_t newValue) 67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org while (1) 69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t oldValue = *theValue; 71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (OSAtomicCompareAndSwap32Barrier(oldValue, newValue, theValue) 72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org == true) 73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return; 75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint32_t AudioDeviceMac::AtomicGet32(int32_t* theValue) 80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org while (1) 82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 8364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org int32_t value = *theValue; 84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (OSAtomicCompareAndSwap32Barrier(value, value, theValue) == true) 85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return value; 87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// CoreAudio errors are best interpreted as four character strings. 92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceMac::logCAMsg(const TraceLevel level, 93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const TraceModule module, 9464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org const int32_t id, const char *msg, 95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const char *err) 96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(msg != NULL); 98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(err != NULL); 99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 100d7e904161d5c59c61cbf094b16bca6e79ada713aandrew@webrtc.org#ifdef WEBRTC_ARCH_BIG_ENDIAN 101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(level, module, id, "%s: %.4s", msg, err); 102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#else 103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We need to flip the characters in this case. 104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(level, module, id, "%s: %.1s%.1s%.1s%.1s", msg, err + 3, err 105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org + 2, err + 1, err); 106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif 107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 10964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioDeviceMac::AudioDeviceMac(const int32_t id) : 110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer(NULL), 111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect(*CriticalSectionWrapper::CreateCriticalSection()), 112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _stopEventRec(*EventWrapper::Create()), 113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _stopEvent(*EventWrapper::Create()), 114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureWorkerThread(NULL), 115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderWorkerThread(NULL), 116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureWorkerThreadId(0), 117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderWorkerThreadId(0), 118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id(id), 119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager(id), 120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inputDeviceIndex(0), 121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outputDeviceIndex(0), 122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inputDeviceID(kAudioObjectUnknown), 123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outputDeviceID(kAudioObjectUnknown), 124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inputDeviceIsSpecified(false), 125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outputDeviceIsSpecified(false), 126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recChannels(N_REC_CHANNELS), 127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playChannels(N_PLAY_CHANNELS), 128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureBufData(NULL), 129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderBufData(NULL), 130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playBufType(AudioDeviceModule::kFixedBufferSize), 131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _initialized(false), 132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _isShutDown(false), 133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recording(false), 134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playing(false), 135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recIsInitialized(false), 136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playIsInitialized(false), 137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _AGC(false), 138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderDeviceIsAlive(1), 139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureDeviceIsAlive(1), 140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _twoDevices(true), 141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStop(false), 142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStopRec(false), 143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _macBookPro(false), 144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _macBookProPanRight(false), 145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureLatencyUs(0), 146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderLatencyUs(0), 147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureDelayUs(0), 148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderDelayUs(0), 149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderDelayOffsetSamples(0), 150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playBufDelayFixed(20), 151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playWarning(0), 152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playError(0), 153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recWarning(0), 154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recError(0), 155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _paCaptureBuffer(NULL), 156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _paRenderBuffer(NULL), 157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureBufSizeSamples(0), 158e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org _renderBufSizeSamples(0), 159e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org prev_key_state_() 160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id, 162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "%s created", __FUNCTION__); 163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(&_stopEvent != NULL); 165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(&_stopEventRec != NULL); 166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(_renderConvertData, 0, sizeof(_renderConvertData)); 168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(&_outStreamFormat, 0, sizeof(AudioStreamBasicDescription)); 169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(&_outDesiredFormat, 0, sizeof(AudioStreamBasicDescription)); 170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(&_inStreamFormat, 0, sizeof(AudioStreamBasicDescription)); 171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(&_inDesiredFormat, 0, sizeof(AudioStreamBasicDescription)); 172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioDeviceMac::~AudioDeviceMac() 176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, 178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "%s destroyed", __FUNCTION__); 179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_isShutDown) 181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org Terminate(); 183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_captureWorkerThread) 186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete _captureWorkerThread; 188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureWorkerThread = NULL; 189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_renderWorkerThread) 192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete _renderWorkerThread; 194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderWorkerThread = NULL; 195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_paRenderBuffer) 198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete _paRenderBuffer; 200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _paRenderBuffer = NULL; 201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_paCaptureBuffer) 204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete _paCaptureBuffer; 206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _paCaptureBuffer = NULL; 207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_renderBufData) 210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete[] _renderBufData; 212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderBufData = NULL; 213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_captureBufData) 216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete[] _captureBufData; 218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureBufData = NULL; 219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kern_return_t kernErr = KERN_SUCCESS; 222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kernErr = semaphore_destroy(mach_task_self(), _renderSemaphore); 223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kernErr != KERN_SUCCESS) 224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " semaphore_destroy() error: %d", kernErr); 227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kernErr = semaphore_destroy(mach_task_self(), _captureSemaphore); 230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kernErr != KERN_SUCCESS) 231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " semaphore_destroy() error: %d", kernErr); 234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete &_stopEvent; 237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete &_stopEventRec; 238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete &_critSect; 239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================ 242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// API 243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================ 244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceMac::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) 246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer = audioBuffer; 251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // inform the AudioBuffer about default settings for this implementation 253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); 254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetPlayoutSampleRate(N_PLAY_SAMPLES_PER_SEC); 255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetRecordingChannels(N_REC_CHANNELS); 256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetPlayoutChannels(N_PLAY_CHANNELS); 257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 25964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::ActiveAudioLayer( 260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceModule::AudioLayer& audioLayer) const 261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org audioLayer = AudioDeviceModule::kPlatformDefaultAudio; 263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 26664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::Init() 267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_initialized) 272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _isShutDown = false; 279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // PortAudio ring buffers require an elementCount which is a power of two. 281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_renderBufData == NULL) 282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 powerOfTwo = 1; 284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org while (powerOfTwo < PLAY_BUF_SIZE_IN_SAMPLES) 285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org powerOfTwo <<= 1; 287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderBufSizeSamples = powerOfTwo; 289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderBufData = new SInt16[_renderBufSizeSamples]; 290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_paRenderBuffer == NULL) 293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _paRenderBuffer = new PaUtilRingBuffer; 295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ring_buffer_size_t bufSize = -1; 296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufSize = PaUtil_InitializeRingBuffer(_paRenderBuffer, sizeof(SInt16), 297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderBufSizeSamples, 298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderBufData); 299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (bufSize == -1) 300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, 302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, " PaUtil_InitializeRingBuffer() error"); 303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_captureBufData == NULL) 308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 powerOfTwo = 1; 310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org while (powerOfTwo < REC_BUF_SIZE_IN_SAMPLES) 311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org powerOfTwo <<= 1; 313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureBufSizeSamples = powerOfTwo; 315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureBufData = new Float32[_captureBufSizeSamples]; 316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_paCaptureBuffer == NULL) 319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _paCaptureBuffer = new PaUtilRingBuffer; 321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ring_buffer_size_t bufSize = -1; 322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufSize = PaUtil_InitializeRingBuffer(_paCaptureBuffer, 323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org sizeof(Float32), 324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureBufSizeSamples, 325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureBufData); 326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (bufSize == -1) 327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, 329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, " PaUtil_InitializeRingBuffer() error"); 330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_renderWorkerThread == NULL) 335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderWorkerThread 337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org = ThreadWrapper::CreateThread(RunRender, this, kRealtimePriority, 338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "RenderWorkerThread"); 339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_renderWorkerThread == NULL) 340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, 342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, " Render CreateThread() error"); 343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_captureWorkerThread == NULL) 348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureWorkerThread 350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org = ThreadWrapper::CreateThread(RunCapture, this, kRealtimePriority, 351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "CaptureWorkerThread"); 352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_captureWorkerThread == NULL) 353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, 355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, " Capture CreateThread() error"); 356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kern_return_t kernErr = KERN_SUCCESS; 361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kernErr = semaphore_create(mach_task_self(), &_renderSemaphore, 362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SYNC_POLICY_FIFO, 0); 363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kernErr != KERN_SUCCESS) 364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, 366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " semaphore_create() error: %d", kernErr); 367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kernErr = semaphore_create(mach_task_self(), &_captureSemaphore, 371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SYNC_POLICY_FIFO, 0); 372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kernErr != KERN_SUCCESS) 373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, 375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " semaphore_create() error: %d", kernErr); 376b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 37964e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // Setting RunLoop to NULL here instructs HAL to manage its own thread for 38064e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // notifications. This was the default behaviour on OS X 10.5 and earlier, 38164e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // but now must be explicitly specified. HAL would otherwise try to use the 38264e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // main thread to issue notifications. 383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress propertyAddress = { 384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioHardwarePropertyRunLoop, 385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyScopeGlobal, 386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyElementMaster }; 387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CFRunLoopRef runLoop = NULL; 388b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = sizeof(CFRunLoopRef); 389b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(kAudioObjectSystemObject, 390b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, size, &runLoop)); 391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Listen for any device changes. 393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioHardwarePropertyDevices; 394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_ERR(AudioObjectAddPropertyListener(kAudioObjectSystemObject, 395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 397b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Determine if this is a MacBook Pro 398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _macBookPro = false; 399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _macBookProPanRight = false; 400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org char buf[128]; 401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size_t length = sizeof(buf); 402b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(buf, 0, length); 403b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int intErr = sysctlbyname("hw.model", buf, &length, NULL, 0); 405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (intErr != 0) 406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Error in sysctlbyname(): %d", err); 409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Hardware model: %s", buf); 413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (strncmp(buf, "MacBookPro", 10) == 0) 414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _macBookPro = true; 416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 418b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playWarning = 0; 420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playError = 0; 421b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recWarning = 0; 422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recError = 0; 423b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _initialized = true; 425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 42964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::Terminate() 430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_initialized) 433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recording) 438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Recording must be stopped"); 441b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_playing) 445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Playback must be stopped"); 448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 451b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Enter(); 452b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.Close(); 454b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int retVal = 0; 457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress propertyAddress = { 459b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, 460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyElementMaster }; 461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(kAudioObjectSystemObject, 462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 463b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org err = AudioHardwareUnload(); 465b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err != noErr) 466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 467b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, 468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Error in AudioHardwareUnload()", (const char*) &err); 469b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org retVal = -1; 470b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); 473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _isShutDown = true; 475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _initialized = false; 476b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outputDeviceIsSpecified = false; 477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inputDeviceIsSpecified = false; 478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return retVal; 480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 481b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::Initialized() const 483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_initialized); 485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 48764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SpeakerIsAvailable(bool& available) 488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 489b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool wasInitialized = _mixerManager.SpeakerIsInitialized(); 491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Make an attempt to open up the 493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // output mixer corresponding to the currently selected output device. 494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized && InitSpeaker() == -1) 496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 499b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 50164e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // Given that InitSpeaker was successful, we know that a valid speaker 50264e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // exists. 503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = true; 504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Close the initialized output mixer 506b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized) 508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseSpeaker(); 510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 511b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 51564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::InitSpeaker() 516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 518b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 520b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_playing) 521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 522b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 525b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (InitDevice(_outputDeviceIndex, _outputDeviceID, false) == -1) 526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 527b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 529b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 530b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_inputDeviceID == _outputDeviceID) 531b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 532b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _twoDevices = false; 533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _twoDevices = true; 536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 537b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 538b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.OpenSpeaker(_outputDeviceID) == -1) 539b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 540b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 541b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 543b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 544b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 545b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 54664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::MicrophoneIsAvailable(bool& available) 547b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 548b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); 550b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Make an attempt to open up the 552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // input mixer corresponding to the currently selected output device. 553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized && InitMicrophone() == -1) 555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 558b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 56064e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // Given that InitMicrophone was successful, we know that a valid microphone 56164e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // exists. 562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = true; 563b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Close the initialized input mixer 565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized) 567b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseMicrophone(); 569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 57464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::InitMicrophone() 575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 578b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recording) 580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 581b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (InitDevice(_inputDeviceIndex, _inputDeviceID, true) == -1) 585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_inputDeviceID == _outputDeviceID) 590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 591b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _twoDevices = false; 592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 593b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _twoDevices = true; 595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.OpenMicrophone(_inputDeviceID) == -1) 598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 600b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::SpeakerIsInitialized() const 606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_mixerManager.SpeakerIsInitialized()); 608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 609b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::MicrophoneIsInitialized() const 611b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_mixerManager.MicrophoneIsInitialized()); 613b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 61564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SpeakerVolumeIsAvailable(bool& available) 616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool wasInitialized = _mixerManager.SpeakerIsInitialized(); 619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Make an attempt to open up the 621b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // output mixer corresponding to the currently selected output device. 622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 623b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized && InitSpeaker() == -1) 624b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 625b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // If we end up here it means that the selected speaker has no volume 626b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // control. 627b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 630b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Given that InitSpeaker was successful, we know that a volume control exists 632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = true; 634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Close the initialized output mixer 636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized) 638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseSpeaker(); 640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 642b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 64564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetSpeakerVolume(uint32_t volume) 646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 647b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_mixerManager.SetSpeakerVolume(volume)); 649b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 65164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SpeakerVolume(uint32_t& volume) const 652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 653b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 65464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t level(0); 655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.SpeakerVolume(level) == -1) 657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 659b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org volume = level; 662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 664b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 66564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetWaveOutVolume(uint16_t volumeLeft, 66664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint16_t volumeRight) 667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 670b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " API call not supported on this platform"); 671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 67464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t 67564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioDeviceMac::WaveOutVolume(uint16_t& /*volumeLeft*/, 67664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint16_t& /*volumeRight*/) const 677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 678b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " API call not supported on this platform"); 681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 68464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::MaxSpeakerVolume(uint32_t& maxVolume) const 685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 68764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t maxVol(0); 688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 689b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.MaxSpeakerVolume(maxVol) == -1) 690b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 691b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 692b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org maxVolume = maxVol; 695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 69864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::MinSpeakerVolume(uint32_t& minVolume) const 699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 70164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t minVol(0); 702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.MinSpeakerVolume(minVol) == -1) 704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 705b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 706b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org minVolume = minVol; 709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 711b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 71264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t 71364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioDeviceMac::SpeakerVolumeStepSize(uint16_t& stepSize) const 714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 715b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 71664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint16_t delta(0); 717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.SpeakerVolumeStepSize(delta) == -1) 719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 721b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 723b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org stepSize = delta; 724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 72764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SpeakerMuteIsAvailable(bool& available) 728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool isAvailable(false); 731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool wasInitialized = _mixerManager.SpeakerIsInitialized(); 732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Make an attempt to open up the 734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // output mixer corresponding to the currently selected output device. 735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized && InitSpeaker() == -1) 737b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 738b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // If we end up here it means that the selected speaker has no volume 739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // control, hence it is safe to state that there is no mute control 740b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // already at this stage. 741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 742b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check if the selected speaker has a mute control 746b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.SpeakerMuteIsAvailable(isAvailable); 748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 749b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = isAvailable; 750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Close the initialized output mixer 752b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized) 754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseSpeaker(); 756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 76164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetSpeakerMute(bool enable) 762b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_mixerManager.SetSpeakerMute(enable)); 764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 76664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SpeakerMute(bool& enabled) const 767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool muted(0); 770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.SpeakerMute(muted) == -1) 772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 774b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 776b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org enabled = muted; 777b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 778b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 78064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::MicrophoneMuteIsAvailable(bool& available) 781b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 783b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool isAvailable(false); 784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); 785b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Make an attempt to open up the 787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // input mixer corresponding to the currently selected input device. 788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized && InitMicrophone() == -1) 790b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 791b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // If we end up here it means that the selected microphone has no volume 792b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // control, hence it is safe to state that there is no boost control 793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // already at this stage. 794b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 795b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 797b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 798b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check if the selected microphone has a mute control 799b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 800b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.MicrophoneMuteIsAvailable(isAvailable); 801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = isAvailable; 802b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Close the initialized input mixer 804b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 805b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized) 806b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 807b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseMicrophone(); 808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 81364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetMicrophoneMute(bool enable) 814b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 815b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_mixerManager.SetMicrophoneMute(enable)); 816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 81864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::MicrophoneMute(bool& enabled) const 819b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 820b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool muted(0); 822b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 823b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.MicrophoneMute(muted) == -1) 824b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 826b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org enabled = muted; 829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 831b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 83264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::MicrophoneBoostIsAvailable(bool& available) 833b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 834b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 835b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool isAvailable(false); 836b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); 837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 838b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Enumerate all avaliable microphone and make an attempt to open up the 839b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // input mixer corresponding to the currently selected input device. 840b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 841b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized && InitMicrophone() == -1) 842b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 843b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // If we end up here it means that the selected microphone has no volume 844b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // control, hence it is safe to state that there is no boost control 845b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // already at this stage. 846b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 847b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 849b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 850b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check if the selected microphone has a boost control 851b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 852b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.MicrophoneBoostIsAvailable(isAvailable); 853b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = isAvailable; 854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 855b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Close the initialized input mixer 856b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 857b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized) 858b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseMicrophone(); 860b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 861b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 862b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 863b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 864b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 86564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetMicrophoneBoost(bool enable) 866b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 867b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_mixerManager.SetMicrophoneBoost(enable)); 869b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 87164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::MicrophoneBoost(bool& enabled) const 872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 873b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 874b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool onOff(0); 875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.MicrophoneBoost(onOff) == -1) 877b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 878b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 879b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 880b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 881b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org enabled = onOff; 882b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 883b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 884b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 88564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::StereoRecordingIsAvailable(bool& available) 886b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 887b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 888b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool isAvailable(false); 889b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); 890b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 891b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized && InitMicrophone() == -1) 892b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 893b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Cannot open the specified device 894b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 895b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 896b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 897b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check if the selected microphone can record stereo 899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 900b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.StereoRecordingIsAvailable(isAvailable); 901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = isAvailable; 902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 903b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Close the initialized input mixer 904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 905b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized) 906b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 907b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseMicrophone(); 908b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 910b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 911b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 912b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 91364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetStereoRecording(bool enable) 914b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (enable) 917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recChannels = 2; 918b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org else 919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recChannels = 1; 920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 923b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 92464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::StereoRecording(bool& enabled) const 925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 926b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recChannels == 2) 928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org enabled = true; 929b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org else 930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org enabled = false; 931b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 934b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 93564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::StereoPlayoutIsAvailable(bool& available) 936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 937b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 938b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool isAvailable(false); 939b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool wasInitialized = _mixerManager.SpeakerIsInitialized(); 940b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 941b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized && InitSpeaker() == -1) 942b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Cannot open the specified device 944b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check if the selected microphone can record stereo 949b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 950b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.StereoPlayoutIsAvailable(isAvailable); 951b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = isAvailable; 952b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 953b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Close the initialized input mixer 954b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 955b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized) 956b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 957b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseSpeaker(); 958b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 959b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 960b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 961b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 962b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 96364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetStereoPlayout(bool enable) 964b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 965b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 966b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (enable) 967b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playChannels = 2; 968b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org else 969b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playChannels = 1; 970b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 971b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 972b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 973b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 97464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::StereoPlayout(bool& enabled) const 975b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 976b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 977b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_playChannels == 2) 978b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org enabled = true; 979b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org else 980b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org enabled = false; 981b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 982b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 983b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 984b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 98564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetAGC(bool enable) 986b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 987b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 988b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _AGC = enable; 989b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 990b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 991b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 992b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 993b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::AGC() const 994b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 995b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 996b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return _AGC; 997b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 998b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 99964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::MicrophoneVolumeIsAvailable(bool& available) 1000b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1001b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1002b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); 1003b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1004b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Make an attempt to open up the 1005b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // input mixer corresponding to the currently selected output device. 1006b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 1007b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized && InitMicrophone() == -1) 1008b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1009b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // If we end up here it means that the selected microphone has no volume 1010b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // control. 1011b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 1012b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1013b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1014b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1015b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Given that InitMicrophone was successful, we know that a volume control 1016b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // exists 1017b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 1018b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = true; 1019b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1020b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Close the initialized input mixer 1021b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 1022b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!wasInitialized) 1023b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1024b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseMicrophone(); 1025b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1026b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1027b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1028b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1029b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 103064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetMicrophoneVolume(uint32_t volume) 1031b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1032b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1033b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_mixerManager.SetMicrophoneVolume(volume)); 1034b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1035b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 103664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::MicrophoneVolume(uint32_t& volume) const 1037b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1038b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 103964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t level(0); 1040b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1041b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.MicrophoneVolume(level) == -1) 1042b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1043b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1044b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " failed to retrive current microphone level"); 1045b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1046b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1047b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1048b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org volume = level; 1049b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1050b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1051b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 105264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t 105364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioDeviceMac::MaxMicrophoneVolume(uint32_t& maxVolume) const 1054b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1055b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 105664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t maxVol(0); 1057b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1058b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1) 1059b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1060b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1061b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1062b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1063b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org maxVolume = maxVol; 1064b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1065b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1066b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 106764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t 106864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioDeviceMac::MinMicrophoneVolume(uint32_t& minVolume) const 1069b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1070b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 107164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t minVol(0); 1072b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1073b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.MinMicrophoneVolume(minVol) == -1) 1074b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1075b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1076b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1077b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1078b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org minVolume = minVol; 1079b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1080b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1081b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 108264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t 108364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioDeviceMac::MicrophoneVolumeStepSize(uint16_t& stepSize) const 1084b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1085b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 108664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint16_t delta(0); 1087b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1088b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_mixerManager.MicrophoneVolumeStepSize(delta) == -1) 1089b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1090b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1091b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1092b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1093b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org stepSize = delta; 1094b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1095b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1096b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 109764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint16_t AudioDeviceMac::PlayoutDevices() 1098b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1099b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID playDevices[MaxNumberDevices]; 1101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return GetNumberDevices(kAudioDevicePropertyScopeOutput, playDevices, 1102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org MaxNumberDevices); 1103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 110564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetPlayoutDevice(uint16_t index) 1106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_playIsInitialized) 1109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID playDevices[MaxNumberDevices]; 111464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t nDevices = GetNumberDevices(kAudioDevicePropertyScopeOutput, 111564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org playDevices, MaxNumberDevices); 1116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " number of availiable waveform-audio output devices is %u", 1118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org nDevices); 1119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (index > (nDevices - 1)) 1121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " device index is out of range [0,%u]", (nDevices - 1)); 1124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outputDeviceIndex = index; 1128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outputDeviceIsSpecified = true; 1129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 113364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetPlayoutDevice( 1134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceModule::WindowsDeviceType /*device*/) 1135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "WindowsDeviceType not supported"); 1138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 114164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::PlayoutDeviceName( 114264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint16_t index, 1143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org char name[kAdmMaxDeviceNameSize], 1144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org char guid[kAdmMaxGuidSize]) 1145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 114764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org const uint16_t nDevices(PlayoutDevices()); 1148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if ((index > (nDevices - 1)) || (name == NULL)) 1150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(name, 0, kAdmMaxDeviceNameSize); 1155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (guid != NULL) 1157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(guid, 0, kAdmMaxGuidSize); 1159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return GetDeviceName(kAudioDevicePropertyScopeOutput, index, name); 1162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 116464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::RecordingDeviceName( 116564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint16_t index, 1166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org char name[kAdmMaxDeviceNameSize], 1167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org char guid[kAdmMaxGuidSize]) 1168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 117064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org const uint16_t nDevices(RecordingDevices()); 1171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if ((index > (nDevices - 1)) || (name == NULL)) 1173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(name, 0, kAdmMaxDeviceNameSize); 1178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (guid != NULL) 1180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(guid, 0, kAdmMaxGuidSize); 1182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return GetDeviceName(kAudioDevicePropertyScopeInput, index, name); 1185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 118764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint16_t AudioDeviceMac::RecordingDevices() 1188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID recDevices[MaxNumberDevices]; 1191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return GetNumberDevices(kAudioDevicePropertyScopeInput, recDevices, 1192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org MaxNumberDevices); 1193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 119564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetRecordingDevice(uint16_t index) 1196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recIsInitialized) 1199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID recDevices[MaxNumberDevices]; 120464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t nDevices = GetNumberDevices(kAudioDevicePropertyScopeInput, 120564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org recDevices, MaxNumberDevices); 1206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " number of availiable waveform-audio input devices is %u", 1208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org nDevices); 1209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (index > (nDevices - 1)) 1211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " device index is out of range [0,%u]", (nDevices - 1)); 1214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inputDeviceIndex = index; 1218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inputDeviceIsSpecified = true; 1219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 122464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t 1225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioDeviceMac::SetRecordingDevice(AudioDeviceModule::WindowsDeviceType /*device*/) 1226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "WindowsDeviceType not supported"); 1229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 123264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::PlayoutIsAvailable(bool& available) 1233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = true; 1236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Try to initialize the playout side 1238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (InitPlayout() == -1) 1239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 1241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We destroy the IOProc created by InitPlayout() in implDeviceIOProc(). 1244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We must actually start playout here in order to have the IOProc 1245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // deleted by calling StopPlayout(). 1246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (StartPlayout() == -1) 1247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 1249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Cancel effect of initialization 1252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (StopPlayout() == -1) 1253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 1255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 126064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::RecordingIsAvailable(bool& available) 1261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = true; 1264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Try to initialize the recording side 1266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (InitRecording() == -1) 1267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 1269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We destroy the IOProc created by InitRecording() in implInDeviceIOProc(). 1272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We must actually start recording here in order to have the IOProc 1273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // deleted by calling StopRecording(). 1274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (StartRecording() == -1) 1275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 1277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Cancel effect of initialization 1280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (StopRecording() == -1) 1281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org available = false; 1283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 128864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::InitPlayout() 1289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 1292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_playing) 1294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_outputDeviceIsSpecified) 1299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_playIsInitialized) 1304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Initialize the speaker (devices might have been added or removed) 1309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (InitSpeaker() == -1) 1310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " InitSpeaker() failed"); 1313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!MicrophoneIsInitialized()) 1316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Make this call to check if we are using 1318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // one or two devices (_twoDevices) 1319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool available = false; 1320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (MicrophoneIsAvailable(available) == -1) 1321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " MicrophoneIsAvailable() failed"); 1324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PaUtil_FlushRingBuffer(_paRenderBuffer); 1328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 1330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = 0; 1331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderDelayOffsetSamples = 0; 1332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderDelayUs = 0; 1333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderLatencyUs = 0; 1334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderDeviceIsAlive = 1; 1335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStop = false; 1336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // The internal microphone of a MacBook Pro is located under the left speaker 1338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // grille. When the internal speakers are in use, we want to fully stereo 1339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // pan to the right. 1340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress 1341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress = { kAudioDevicePropertyDataSource, 1342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioDevicePropertyScopeOutput, 0 }; 1343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_macBookPro) 1344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _macBookProPanRight = false; 1346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID, 1347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress); 1348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (hasProperty) 1349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 dataSource = 0; 1351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(dataSource); 1352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectGetPropertyData(_outputDeviceID, 1353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &dataSource)); 1354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (dataSource == 'ispk') 1356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _macBookProPanRight = true; 1358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, 1359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, 1360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "MacBook Pro using internal speakers; stereo" 1361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " panning right"); 1362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 1363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, 1365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, "MacBook Pro not using internal speakers"); 1366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 136864e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // Add a listener to determine if the status changes. 1369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener(_outputDeviceID, 1370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 1371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 137464e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // Get current stream description 1375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; 1376b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(&_outStreamFormat, 0, sizeof(_outStreamFormat)); 1377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(_outStreamFormat); 1378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, 1379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &_outStreamFormat)); 1380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_outStreamFormat.mFormatID != kAudioFormatLinearPCM) 1382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, 1384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Unacceptable output stream format -> mFormatID", 1385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (const char *) &_outStreamFormat.mFormatID); 1386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1388b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1389b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_outStreamFormat.mChannelsPerFrame > N_DEVICE_CHANNELS) 1390b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 139264e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org "Too many channels on output device (mChannelsPerFrame = %d)", 139364e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org _outStreamFormat.mChannelsPerFrame); 1394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1397b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_outStreamFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) 1398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Non-interleaved audio data is not supported.", 1401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "AudioHardware streams should not have this format."); 1402b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1403b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Ouput stream format:"); 1407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "mSampleRate = %f, mChannelsPerFrame = %u", 1409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outStreamFormat.mSampleRate, 1410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outStreamFormat.mChannelsPerFrame); 1411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "mBytesPerPacket = %u, mFramesPerPacket = %u", 1413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outStreamFormat.mBytesPerPacket, 1414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outStreamFormat.mFramesPerPacket); 1415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "mBytesPerFrame = %u, mBitsPerChannel = %u", 1417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outStreamFormat.mBytesPerFrame, 1418b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outStreamFormat.mBitsPerChannel); 1419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 142064e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org "mFormatFlags = %u", 142164e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org _outStreamFormat.mFormatFlags); 1422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceInfo, kTraceAudioDevice, _id, "mFormatID", 1423b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (const char *) &_outStreamFormat.mFormatID); 1424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 142564e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // Our preferred format to work with 1426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mSampleRate = N_PLAY_SAMPLES_PER_SEC; 1427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_outStreamFormat.mChannelsPerFrame >= 2 && (_playChannels == 2)) 1428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mChannelsPerFrame = 2; 1430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 1431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Disable stereo playout when we only have one channel on the device. 1433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mChannelsPerFrame = 1; 1434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playChannels = 1; 1435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Stereo playout unavailable on this device"); 1437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_ptrAudioBuffer) 1440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1441b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Update audio buffer with the selected parameters 1442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetPlayoutSampleRate(N_PLAY_SAMPLES_PER_SEC); 144364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _ptrAudioBuffer->SetPlayoutChannels((uint8_t) _playChannels); 1444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderDelayOffsetSamples = _renderBufSizeSamples - N_BUFFERS_OUT 1447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * ENGINE_PLAY_BUF_SIZE_IN_SAMPLES * _outDesiredFormat.mChannelsPerFrame; 1448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mBytesPerPacket = _outDesiredFormat.mChannelsPerFrame 1450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * sizeof(SInt16); 145164e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org _outDesiredFormat.mFramesPerPacket = 1; // In uncompressed audio, 1452b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // a packet is one frame. 1453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mBytesPerFrame = _outDesiredFormat.mChannelsPerFrame 1454b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * sizeof(SInt16); 1455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mBitsPerChannel = sizeof(SInt16) * 8; 1456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger 1458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org | kLinearPCMFormatFlagIsPacked; 1459d7e904161d5c59c61cbf094b16bca6e79ada713aandrew@webrtc.org#ifdef WEBRTC_ARCH_BIG_ENDIAN 1460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; 1461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif 1462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mFormatID = kAudioFormatLinearPCM; 1463b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew(&_outDesiredFormat, &_outStreamFormat, 1465b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &_renderConverter)); 1466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1467b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // First try to set buffer size to desired value (_playBufDelayFixed) 1468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 bufByteCount = (UInt32)((_outStreamFormat.mSampleRate / 1000.0) 1469b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _playBufDelayFixed * _outStreamFormat.mChannelsPerFrame 1470b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * sizeof(Float32)); 1471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_outStreamFormat.mFramesPerPacket != 0) 1472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (bufByteCount % _outStreamFormat.mFramesPerPacket != 0) 1474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufByteCount = ((UInt32)(bufByteCount 1476b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org / _outStreamFormat.mFramesPerPacket) + 1) 1477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _outStreamFormat.mFramesPerPacket; 1478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1481b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Ensure the buffer size is within the acceptable range provided by the device. 1482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyBufferSizeRange; 1483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioValueRange range; 1484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(range); 1485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, 1486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &range)); 1487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (range.mMinimum > bufByteCount) 1488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1489b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufByteCount = range.mMinimum; 1490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (range.mMaximum < bufByteCount) 1491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufByteCount = range.mMaximum; 1493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyBufferSize; 1496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(bufByteCount); 1497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, 1498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, size, &bufByteCount)); 1499b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Get render device latency 1501b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyLatency; 1502b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 latency = 0; 1503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(UInt32); 1504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, 1505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &latency)); 150664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _renderLatencyUs = (uint32_t) ((1.0e6 * latency) 1507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org / _outStreamFormat.mSampleRate); 1508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Get render stream latency 1510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyStreams; 1511b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioStreamID stream = 0; 1512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(AudioStreamID); 1513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, 1514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &stream)); 1515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioStreamPropertyLatency; 1516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(UInt32); 1517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org latency = 0; 1518b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, 1519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &latency)); 152064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _renderLatencyUs += (uint32_t) ((1.0e6 * latency) 1521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org / _outStreamFormat.mSampleRate); 1522b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Listen for format changes 1524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; 1525b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectAddPropertyListener(_outputDeviceID, 1526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 1527b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Listen for processor overloads 1529b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDeviceProcessorOverload; 1530b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener(_outputDeviceID, 1531b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 1532b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_twoDevices || !_recIsInitialized) 1534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioDeviceCreateIOProcID(_outputDeviceID, 1536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org deviceIOProc, this, &_deviceIOProcID)); 1537b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1538b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1539b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Mark playout side as initialized 1540b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playIsInitialized = true; 1541b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1543b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " initial playout status: _renderDelayOffsetSamples=%d," 1544b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " _renderDelayUs=%d, _renderLatencyUs=%d", 1545b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderDelayOffsetSamples, _renderDelayUs, _renderLatencyUs); 1546b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1547b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1548b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 155064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::InitRecording() 1551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 1554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recording) 1556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1558b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1560b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_inputDeviceIsSpecified) 1561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1563b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recIsInitialized) 1566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1567b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Initialize the microphone (devices might have been added or removed) 1571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (InitMicrophone() == -1) 1572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " InitMicrophone() failed"); 1575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!SpeakerIsInitialized()) 1578b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Make this call to check if we are using 1580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // one or two devices (_twoDevices) 1581b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool available = false; 1582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (SpeakerIsAvailable(available) == -1) 1583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " SpeakerIsAvailable() failed"); 1586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 1590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = 0; 1591b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PaUtil_FlushRingBuffer(_paCaptureBuffer); 1593b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureDelayUs = 0; 1595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureLatencyUs = 0; 1596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureDeviceIsAlive = 1; 1597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStopRec = false; 1598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 159964e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // Get current stream description 1600b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress 1601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress = { kAudioDevicePropertyStreamFormat, 1602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioDevicePropertyScopeInput, 0 }; 1603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(&_inStreamFormat, 0, sizeof(_inStreamFormat)); 1604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(_inStreamFormat); 1605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, 1606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &_inStreamFormat)); 1607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_inStreamFormat.mFormatID != kAudioFormatLinearPCM) 1609b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, 1611b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Unacceptable input stream format -> mFormatID", 1612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (const char *) &_inStreamFormat.mFormatID); 1613b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1615b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_inStreamFormat.mChannelsPerFrame > N_DEVICE_CHANNELS) 1617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 161964e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org "Too many channels on input device (mChannelsPerFrame = %d)", 162064e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org _inStreamFormat.mChannelsPerFrame); 162164e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org return -1; 162264e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org } 162364e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org 162464e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org const int io_block_size_samples = _inStreamFormat.mChannelsPerFrame * 162564e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org _inStreamFormat.mSampleRate / 100 * N_BLOCKS_IO; 162664e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org if (io_block_size_samples > _captureBufSizeSamples) 162764e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org { 162864e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 162964e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org "Input IO block size (%d) is larger than ring buffer (%u)", 163064e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org io_block_size_samples, _captureBufSizeSamples); 1631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Input stream format:"); 1636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " mSampleRate = %f, mChannelsPerFrame = %u", 1638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inStreamFormat.mSampleRate, _inStreamFormat.mChannelsPerFrame); 1639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " mBytesPerPacket = %u, mFramesPerPacket = %u", 1641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inStreamFormat.mBytesPerPacket, 1642b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inStreamFormat.mFramesPerPacket); 1643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " mBytesPerFrame = %u, mBitsPerChannel = %u", 1645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inStreamFormat.mBytesPerFrame, 1646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inStreamFormat.mBitsPerChannel); 1647b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 164864e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org " mFormatFlags = %u", 164964e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org _inStreamFormat.mFormatFlags); 1650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceInfo, kTraceAudioDevice, _id, "mFormatID", 1651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (const char *) &_inStreamFormat.mFormatID); 1652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1653b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Our preferred format to work with 1654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_inStreamFormat.mChannelsPerFrame >= 2 && (_recChannels == 2)) 1655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mChannelsPerFrame = 2; 1657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 1658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1659b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Disable stereo recording when we only have one channel on the device. 1660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mChannelsPerFrame = 1; 1661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recChannels = 1; 1662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Stereo recording unavailable on this device"); 1664b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1665b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1666b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_ptrAudioBuffer) 1667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Update audio buffer with the selected parameters 1669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); 167064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _ptrAudioBuffer->SetRecordingChannels((uint8_t) _recChannels); 1671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mSampleRate = N_REC_SAMPLES_PER_SEC; 1674b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mBytesPerPacket = _inDesiredFormat.mChannelsPerFrame 1675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * sizeof(SInt16); 1676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mFramesPerPacket = 1; 1677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mBytesPerFrame = _inDesiredFormat.mChannelsPerFrame 1678b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * sizeof(SInt16); 1679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mBitsPerChannel = sizeof(SInt16) * 8; 1680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger 1682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org | kLinearPCMFormatFlagIsPacked; 1683d7e904161d5c59c61cbf094b16bca6e79ada713aandrew@webrtc.org#ifdef WEBRTC_ARCH_BIG_ENDIAN 1684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; 1685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif 1686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mFormatID = kAudioFormatLinearPCM; 1687b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew(&_inStreamFormat, &_inDesiredFormat, 1689b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &_captureConverter)); 1690b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1691b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // First try to set buffer size to desired value (10 ms * N_BLOCKS_IO) 1692b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(xians): investigate this block. 1693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 bufByteCount = (UInt32)((_inStreamFormat.mSampleRate / 1000.0) 1694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 10.0 * N_BLOCKS_IO * _inStreamFormat.mChannelsPerFrame 1695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * sizeof(Float32)); 1696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_inStreamFormat.mFramesPerPacket != 0) 1697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (bufByteCount % _inStreamFormat.mFramesPerPacket != 0) 1699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufByteCount = ((UInt32)(bufByteCount 1701b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org / _inStreamFormat.mFramesPerPacket) + 1) 1702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _inStreamFormat.mFramesPerPacket; 1703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1705b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1706b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Ensure the buffer size is within the acceptable range provided by the device. 1707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyBufferSizeRange; 1708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioValueRange range; 1709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(range); 1710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, 1711b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &range)); 1712b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (range.mMinimum > bufByteCount) 1713b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufByteCount = range.mMinimum; 1715b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (range.mMaximum < bufByteCount) 1716b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufByteCount = range.mMaximum; 1718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyBufferSize; 1721b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(bufByteCount); 1722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, 1723b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, size, &bufByteCount)); 1724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Get capture device latency 1726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyLatency; 1727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 latency = 0; 1728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(UInt32); 1729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, 1730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &latency)); 1731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureLatencyUs = (UInt32)((1.0e6 * latency) 1732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org / _inStreamFormat.mSampleRate); 1733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Get capture stream latency 1735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyStreams; 1736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioStreamID stream = 0; 1737b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(AudioStreamID); 1738b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, 1739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &stream)); 1740b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioStreamPropertyLatency; 1741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(UInt32); 1742b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org latency = 0; 1743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, 1744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &latency)); 1745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureLatencyUs += (UInt32)((1.0e6 * latency) 1746b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org / _inStreamFormat.mSampleRate); 1747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Listen for format changes 1749b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(xians): should we be using kAudioDevicePropertyDeviceHasChanged? 1750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; 1751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectAddPropertyListener(_inputDeviceID, 1752b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 1753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Listen for processor overloads 1755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDeviceProcessorOverload; 1756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener(_inputDeviceID, 1757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 1758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_twoDevices) 1760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioDeviceCreateIOProcID(_inputDeviceID, 1762b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org inDeviceIOProc, this, &_inDeviceIOProcID)); 1763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (!_playIsInitialized) 1764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioDeviceCreateIOProcID(_inputDeviceID, 1766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org deviceIOProc, this, &_deviceIOProcID)); 1767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Mark recording side as initialized 1770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recIsInitialized = true; 1771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1774b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 177564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::StartRecording() 1776b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1777b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1778b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 1779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1780b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_recIsInitialized) 1781b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1783b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1785b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recording) 1786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1790b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_initialized) 1791b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1792b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Recording worker thread has not been started"); 1794b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1795b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1797b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 1798b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1799b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org unsigned int threadID(0); 1800b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_captureWorkerThread != NULL) 1801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1802b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureWorkerThread->Start(threadID); 1803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1804b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _captureWorkerThreadId = threadID; 1805b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1806b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_twoDevices) 1807b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioDeviceStart(_inputDeviceID, _inDeviceIOProcID)); 1809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (!_playing) 1810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioDeviceStart(_inputDeviceID, _deviceIOProcID)); 1812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1813b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1814b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recording = true; 1815b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1818b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 181964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::StopRecording() 1820b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1822b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 1823b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1824b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_recIsInitialized) 1825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1826b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 1830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1831b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Stop device 1832b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t captureDeviceIsAlive = AtomicGet32(&_captureDeviceIsAlive); 1833b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_twoDevices) 1834b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1835b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recording && captureDeviceIsAlive == 1) 1836b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recording = false; 1838b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStopRec = true; // Signal to io proc to stop audio device 1839b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); // Cannot be under lock, risk of deadlock 1840b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kEventTimeout == _stopEventRec.Wait(2000)) 1841b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1842b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped critScoped(&_critSect); 1843b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1844b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Timed out stopping the capture IOProc. " 1845b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "We may have failed to detect a device removal."); 1846b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1847b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioDeviceStop(_inputDeviceID, 1848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDeviceIOProcID)); 1849b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN( 1850b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceDestroyIOProcID(_inputDeviceID, 1851b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDeviceIOProcID)); 1852b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1853b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Enter(); 1854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStopRec = false; 1855b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, 1856b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Recording stopped"); 1857b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1858b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org else 1860b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1861b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We signal a stop for a shared device even when rendering has 1862b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // not yet ended. This is to ensure the IOProc will return early as 1863b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // intended (by checking |_recording|) before accessing 1864b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // resources we free below (e.g. the capture converter). 1865b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 1866b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // In the case of a shared devcie, the IOProc will verify 1867b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // rendering has ended before stopping itself. 1868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recording && captureDeviceIsAlive == 1) 1869b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recording = false; 1871b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStop = true; // Signal to io proc to stop audio device 1872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); // Cannot be under lock, risk of deadlock 1873b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kEventTimeout == _stopEvent.Wait(2000)) 1874b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped critScoped(&_critSect); 1876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1877b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Timed out stopping the shared IOProc. " 1878b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "We may have failed to detect a device removal."); 1879b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1880b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We assume rendering on a shared device has stopped as well if 1881b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // the IOProc times out. 1882b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioDeviceStop(_outputDeviceID, 1883b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _deviceIOProcID)); 1884b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioDeviceDestroyIOProcID(_outputDeviceID, 1885b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _deviceIOProcID)); 1886b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1887b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Enter(); 1888b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStop = false; 1889b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, 1890b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Recording stopped (shared)"); 1891b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1892b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1893b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1894b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Setting this signal will allow the worker thread to be stopped. 1895b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AtomicSet32(&_captureDeviceIsAlive, 0); 1896b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); 1897b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_captureWorkerThread != NULL) 1898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_captureWorkerThread->Stop()) 1900b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Timed out waiting for the render worker thread to " 1903b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "stop."); 1904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1905b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1906b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Enter(); 1907b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1908b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioConverterDispose(_captureConverter)); 1909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1910b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Remove listeners. 1911b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress 1912b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress = { kAudioDevicePropertyStreamFormat, 1913b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioDevicePropertyScopeInput, 0 }; 1914b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_inputDeviceID, 1915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 1916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDeviceProcessorOverload; 1918b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_inputDeviceID, 1919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 1920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recIsInitialized = false; 1922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recording = false; 1923b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1924b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1926b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::RecordingIsInitialized() const 1928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1929b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_recIsInitialized); 1930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1931b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::Recording() const 1933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1934b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_recording); 1935b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1937b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::PlayoutIsInitialized() const 1938b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1939b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_playIsInitialized); 1940b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1941b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 194264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::StartPlayout() 1943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 194464e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org 1945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 1946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_playIsInitialized) 1948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1949b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 1950b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1951b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1952b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_playing) 1953b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1954b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1955b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1956b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1957b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 1958b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1959b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org unsigned int threadID(0); 1960b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_renderWorkerThread != NULL) 1961b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1962b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderWorkerThread->Start(threadID); 1963b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1964b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderWorkerThreadId = threadID; 1965b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1966b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_twoDevices || !_recording) 1967b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1968b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioDeviceStart(_outputDeviceID, _deviceIOProcID)); 1969b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1970b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playing = true; 1971b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1972b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1973b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 1974b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 197564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::StopPlayout() 1976b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 1977b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1978b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped lock(&_critSect); 1979b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1980b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_playIsInitialized) 1981b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1982b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 1983b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1984b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1985b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 1986b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1987b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t renderDeviceIsAlive = AtomicGet32(&_renderDeviceIsAlive); 1988b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_playing && renderDeviceIsAlive == 1) 1989b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 1990b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We signal a stop for a shared device even when capturing has not 1991b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // yet ended. This is to ensure the IOProc will return early as 1992b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // intended (by checking |_playing|) before accessing resources we 1993b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // free below (e.g. the render converter). 1994b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 1995b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // In the case of a shared device, the IOProc will verify capturing 1996b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // has ended before stopping itself. 1997b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playing = false; 1998b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStop = true; // Signal to io proc to stop audio device 1999b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); // Cannot be under lock, risk of deadlock 2000b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kEventTimeout == _stopEvent.Wait(2000)) 2001b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2002b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CriticalSectionScoped critScoped(&_critSect); 2003b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 2004b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Timed out stopping the render IOProc. " 2005b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "We may have failed to detect a device removal."); 2006b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2007b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We assume capturing on a shared device has stopped as well if the 2008b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // IOProc times out. 2009b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioDeviceStop(_outputDeviceID, 2010b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _deviceIOProcID)); 2011b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioDeviceDestroyIOProcID(_outputDeviceID, 2012b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _deviceIOProcID)); 2013b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2014b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Enter(); 2015b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStop = false; 2016b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, 2017b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Playout stopped"); 2018b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2019b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2020b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Setting this signal will allow the worker thread to be stopped. 2021b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AtomicSet32(&_renderDeviceIsAlive, 0); 2022b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); 2023b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_renderWorkerThread != NULL) 2024b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2025b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_renderWorkerThread->Stop()) 2026b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2027b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 2028b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Timed out waiting for the render worker thread to " 2029b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "stop."); 2030b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2031b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2032b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Enter(); 2033b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2034b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioConverterDispose(_renderConverter)); 2035b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2036b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Remove listeners. 2037b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress propertyAddress = { 2038b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeOutput, 2039b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 0 }; 2040b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_outputDeviceID, 2041b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 2042b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2043b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDeviceProcessorOverload; 2044b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_outputDeviceID, 2045b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 2046b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2047b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_macBookPro) 2048b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2049b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID, 2050b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress); 2051b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (hasProperty) 2052b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2053b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyDataSource; 2054b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(_outputDeviceID, 2055b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, &objectListenerProc, this)); 2056b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2057b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2058b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2059b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playIsInitialized = false; 2060b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playing = false; 2061b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2062b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2063b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2064b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 206564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::PlayoutDelay(uint16_t& delayMS) const 2066b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2067b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t renderDelayUs = AtomicGet32(&_renderDelayUs); 206864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org delayMS = static_cast<uint16_t> (1e-3 * (renderDelayUs + _renderLatencyUs) + 206964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org 0.5); 2070b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2071b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2072b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 207364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::RecordingDelay(uint16_t& delayMS) const 2074b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2075b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t captureDelayUs = AtomicGet32(&_captureDelayUs); 207664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org delayMS = static_cast<uint16_t> (1e-3 * (captureDelayUs + 207764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _captureLatencyUs) + 0.5); 2078b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2079b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2080b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2081b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::Playing() const 2082b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2083b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_playing); 2084b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2085b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 208664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::SetPlayoutBuffer( 2087b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioDeviceModule::BufferType type, 208864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint16_t sizeMS) 2089b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2090b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2091b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (type != AudioDeviceModule::kFixedBufferSize) 2092b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2093b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 2094b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Adaptive buffer size not supported on this platform"); 2095b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2096b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2097b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2098b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playBufType = type; 2099b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playBufDelayFixed = sizeMS; 2100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 210364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::PlayoutBuffer( 2104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceModule::BufferType& type, 210564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint16_t& sizeMS) const 2106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org type = _playBufType; 2109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org sizeMS = _playBufDelayFixed; 2110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Not implemented for Mac. 211564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::CPULoad(uint16_t& /*load*/) const 2116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 2119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " API call not supported on this platform"); 2120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::PlayoutWarning() const 2125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_playWarning > 0); 2127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::PlayoutError() const 2130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_playError > 0); 2132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::RecordingWarning() const 2135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_recWarning > 0); 2137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::RecordingError() const 2140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (_recError > 0); 2142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceMac::ClearPlayoutWarning() 2145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playWarning = 0; 2147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceMac::ClearPlayoutError() 2150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playError = 0; 2152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceMac::ClearRecordingWarning() 2155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recWarning = 0; 2157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioDeviceMac::ClearRecordingError() 2160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recError = 0; 2162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================ 2165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Private Methods 2166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================ 2167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 216864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t 2169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioDeviceMac::GetNumberDevices(const AudioObjectPropertyScope scope, 2170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID scopedDeviceIds[], 217164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org const uint32_t deviceListLength) 2172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 2174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress propertyAddress = { 2176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, 2177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyElementMaster }; 2178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = 0; 2179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, 2180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size)); 2181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (size == 0) 2182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 2184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "No devices"); 2185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID* deviceIds = (AudioDeviceID*) malloc(size); 2189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 numberDevices = size / sizeof(AudioDeviceID); 2190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioBufferList* bufferList = NULL; 2191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 numberScopedDevices = 0; 2192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // First check if there is a default device and list it 2194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 hardwareProperty = 0; 2195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (scope == kAudioDevicePropertyScopeOutput) 2196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org hardwareProperty = kAudioHardwarePropertyDefaultOutputDevice; 2198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org hardwareProperty = kAudioHardwarePropertyDefaultInputDevice; 2201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress 2204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddressDefault = { hardwareProperty, 2205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyScopeGlobal, 2206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyElementMaster }; 2207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID usedID; 2209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 uintSize = sizeof(UInt32); 2210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(kAudioObjectSystemObject, 2211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddressDefault, 0, NULL, &uintSize, &usedID)); 2212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (usedID != kAudioDeviceUnknown) 2213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org scopedDeviceIds[numberScopedDevices] = usedID; 2215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org numberScopedDevices++; 2216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 2219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "GetNumberDevices(): Default device unknown"); 2220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Then list the rest of the devices 2223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool listOK = true; 2224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_ERR(AudioObjectGetPropertyData(kAudioObjectSystemObject, 2226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, deviceIds)); 2227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err != noErr) 2228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org listOK = false; 2230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; 2233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mScope = scope; 2234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mElement = 0; 2235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org for (UInt32 i = 0; i < numberDevices; i++) 2236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check for input channels 2238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_ERR(AudioObjectGetPropertyDataSize(deviceIds[i], 2239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size)); 2240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err == kAudioHardwareBadDeviceError) 2241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // This device doesn't actually exist; continue iterating. 2243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org continue; 2244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (err != noErr) 2245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org listOK = false; 2247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org break; 2248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufferList = (AudioBufferList*) malloc(size); 2251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_ERR(AudioObjectGetPropertyData(deviceIds[i], 2252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, bufferList)); 2253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err != noErr) 2254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org listOK = false; 2256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org break; 2257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (bufferList->mNumberBuffers > 0) 2260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (numberScopedDevices >= deviceListLength) 2262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, 2264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kTraceAudioDevice, _id, 2265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Device list is not long enough"); 2266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org listOK = false; 2267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org break; 2268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org scopedDeviceIds[numberScopedDevices] = deviceIds[i]; 2271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org numberScopedDevices++; 2272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org free(bufferList); 2275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufferList = NULL; 22763b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org } // for 2277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!listOK) 2280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (deviceIds) 2282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org free(deviceIds); 2284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org deviceIds = NULL; 2285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (bufferList) 2288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org free(bufferList); 2290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bufferList = NULL; 2291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 229664e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // Happy ending 2297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (deviceIds) 2298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org free(deviceIds); 2300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org deviceIds = NULL; 2301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return numberScopedDevices; 2304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 230664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t 2307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioDeviceMac::GetDeviceName(const AudioObjectPropertyScope scope, 230864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org const uint16_t index, 2309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org char* name) 2310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 2312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 len = kAdmMaxDeviceNameSize; 2313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID deviceIds[MaxNumberDevices]; 2314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int numberDevices = GetNumberDevices(scope, deviceIds, MaxNumberDevices); 2316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (numberDevices < 0) 2317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (numberDevices == 0) 2320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 2322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "No devices"); 2323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // If the number is below the number of devices, assume it's "WEBRTC ID" 2327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // otherwise assume it's a CoreAudio ID 2328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID usedID; 2329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check if there is a default device 2331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool isDefaultDevice = false; 2332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (index == 0) 2333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 hardwareProperty = 0; 2335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (scope == kAudioDevicePropertyScopeOutput) 2336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org hardwareProperty = kAudioHardwarePropertyDefaultOutputDevice; 2338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org hardwareProperty = kAudioHardwarePropertyDefaultInputDevice; 2341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress propertyAddress = { hardwareProperty, 2343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyScopeGlobal, 2344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyElementMaster }; 2345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = sizeof(UInt32); 2346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(kAudioObjectSystemObject, 2347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &usedID)); 2348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (usedID == kAudioDeviceUnknown) 2349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 2351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "GetDeviceName(): Default device unknown"); 2352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org isDefaultDevice = true; 2355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress propertyAddress = { 2359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioDevicePropertyDeviceName, scope, 0 }; 2360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (isDefaultDevice) 2362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org char devName[len]; 2364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(usedID, 2366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &len, devName)); 2367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org sprintf(name, "default (%s)", devName); 2369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (index < numberDevices) 2372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org usedID = deviceIds[index]; 2374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2376b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org usedID = index; 2377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(usedID, 2380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &len, name)); 2381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 238664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::InitDevice(const uint16_t userDeviceIndex, 238764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org AudioDeviceID& deviceId, 238864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org const bool isInput) 2389b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2390b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 2391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = 0; 2392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyScope deviceScope; 2393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertySelector defaultDeviceSelector; 2394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceID deviceIds[MaxNumberDevices]; 2395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (isInput) 2397b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org deviceScope = kAudioDevicePropertyScopeInput; 2399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org defaultDeviceSelector = kAudioHardwarePropertyDefaultInputDevice; 2400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2402b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org deviceScope = kAudioDevicePropertyScopeOutput; 2403b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org defaultDeviceSelector = kAudioHardwarePropertyDefaultOutputDevice; 2404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress 2407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress = { defaultDeviceSelector, 2408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyScopeGlobal, 2409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioObjectPropertyElementMaster }; 2410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Get the actual device IDs 2412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int numberDevices = GetNumberDevices(deviceScope, deviceIds, 2413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org MaxNumberDevices); 2414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (numberDevices < 0) 2415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (numberDevices == 0) 2418b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 2420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "InitDevice(): No devices"); 2421b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2423b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org bool isDefaultDevice = false; 2425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org deviceId = kAudioDeviceUnknown; 2426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (userDeviceIndex == 0) 2427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Try to use default system device 2429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(AudioDeviceID); 2430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(kAudioObjectSystemObject, 2431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &deviceId)); 2432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (deviceId == kAudioDeviceUnknown) 2433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 2435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " No default device exists"); 2436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org isDefaultDevice = true; 2439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2441b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!isDefaultDevice) 2443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org deviceId = deviceIds[userDeviceIndex]; 2445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Obtain device name and manufacturer for logging. 244864e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org // Also use this as a test to ensure a user-set device ID is valid. 2449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org char devName[128]; 2450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org char devManf[128]; 2451b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(devName, 0, sizeof(devName)); 2452b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(devManf, 0, sizeof(devManf)); 2453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2454b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyDeviceName; 2455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mScope = deviceScope; 2456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mElement = 0; 2457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(devName); 2458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(deviceId, 2459b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, devName)); 2460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org propertyAddress.mSelector = kAudioDevicePropertyDeviceManufacturer; 2462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org size = sizeof(devManf); 2463b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(deviceId, 2464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, devManf)); 2465b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (isInput) 2467b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2469b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Input device: %s %s", devManf, devName); 2470b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Output device: %s %s", devManf, devName); 2474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2476b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::objectListenerProc( 2480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectID objectId, 2481b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 numberAddresses, 2482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioObjectPropertyAddress addresses[], 2483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org void* clientData) 2484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceMac *ptrThis = (AudioDeviceMac *) clientData; 2486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(ptrThis != NULL); 2487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ptrThis->implObjectListenerProc(objectId, numberAddresses, addresses); 2489b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // AudioObjectPropertyListenerProc functions are supposed to return 0 2491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::implObjectListenerProc( 2495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioObjectID objectId, 2496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const UInt32 numberAddresses, 2497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioObjectPropertyAddress addresses[]) 2498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2499b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, 2500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "AudioDeviceMac::implObjectListenerProc()"); 250164e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org 2502b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org for (UInt32 i = 0; i < numberAddresses; i++) 2503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (addresses[i].mSelector == kAudioHardwarePropertyDevices) 2505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2506b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org HandleDeviceChange(); 2507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (addresses[i].mSelector == kAudioDevicePropertyStreamFormat) 2508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org HandleStreamFormatChange(objectId, addresses[i]); 2510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (addresses[i].mSelector == kAudioDevicePropertyDataSource) 2511b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org HandleDataSourceChange(objectId, addresses[i]); 2513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (addresses[i].mSelector == kAudioDeviceProcessorOverload) 2514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org HandleProcessorOverload(addresses[i]); 2516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2518b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2520b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 252264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::HandleDeviceChange() 2523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 2525b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, 2527b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "kAudioHardwarePropertyDevices"); 2528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2529b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // A device has changed. Check if our registered devices have been removed. 2530b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Ensure the devices have been initialized, meaning the IDs are valid. 2531b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (MicrophoneIsInitialized()) 2532b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress propertyAddress = { 2534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioDevicePropertyDeviceIsAlive, 2535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioDevicePropertyScopeInput, 0 }; 2536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 deviceIsAlive = 1; 2537b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = sizeof(UInt32); 2538b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org err = AudioObjectGetPropertyData(_inputDeviceID, &propertyAddress, 0, 2539b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org NULL, &size, &deviceIsAlive); 2540b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2541b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err == kAudioHardwareBadDeviceError || deviceIsAlive == 0) 2542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2543b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 2544b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Capture device is not alive (probably removed)"); 2545b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AtomicSet32(&_captureDeviceIsAlive, 0); 2546b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseMicrophone(); 2547b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_recError == 1) 2548b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, 2550b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, " pending recording error exists"); 2551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recError = 1; // triggers callback from module process thread 2553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (err != noErr) 2554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, 2556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Error in AudioDeviceGetProperty()", (const char*) &err); 2557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 255864e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org } 2559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2560b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (SpeakerIsInitialized()) 2562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2563b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioObjectPropertyAddress propertyAddress = { 2564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioDevicePropertyDeviceIsAlive, 2565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kAudioDevicePropertyScopeOutput, 0 }; 2566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 deviceIsAlive = 1; 2567b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = sizeof(UInt32); 2568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org err = AudioObjectGetPropertyData(_outputDeviceID, &propertyAddress, 0, 2569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org NULL, &size, &deviceIsAlive); 2570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err == kAudioHardwareBadDeviceError || deviceIsAlive == 0) 2572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 2574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Render device is not alive (probably removed)"); 2575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AtomicSet32(&_renderDeviceIsAlive, 0); 2576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _mixerManager.CloseSpeaker(); 2577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_playError == 1) 2578b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, 2580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, " pending playout error exists"); 2581b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playError = 1; // triggers callback from module process thread 2583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (err != noErr) 2584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, 2586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Error in AudioDeviceGetProperty()", (const char*) &err); 2587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2591b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2593b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 259464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::HandleStreamFormatChange( 2595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioObjectID objectId, 2596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioObjectPropertyAddress propertyAddress) 2597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 2599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2600b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, 2601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Stream format changed"); 2602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (objectId != _inputDeviceID && objectId != _outputDeviceID) 2604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Get the new device format 2609b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioStreamBasicDescription streamFormat; 2610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = sizeof(streamFormat); 2611b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(objectId, 2612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &streamFormat)); 2613b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (streamFormat.mFormatID != kAudioFormatLinearPCM) 2615b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, 2617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Unacceptable input stream format -> mFormatID", 2618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (const char *) &streamFormat.mFormatID); 2619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2621b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (streamFormat.mChannelsPerFrame > N_DEVICE_CHANNELS) 2623b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2624b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 2625b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Too many channels on device (mChannelsPerFrame = %d)", 2626b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org streamFormat.mChannelsPerFrame); 2627b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 2628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2630b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Stream format:"); 2632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "mSampleRate = %f, mChannelsPerFrame = %u", 2634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org streamFormat.mSampleRate, streamFormat.mChannelsPerFrame); 2635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "mBytesPerPacket = %u, mFramesPerPacket = %u", 2637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org streamFormat.mBytesPerPacket, streamFormat.mFramesPerPacket); 2638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "mBytesPerFrame = %u, mBitsPerChannel = %u", 2640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org streamFormat.mBytesPerFrame, streamFormat.mBitsPerChannel); 2641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 264264e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org "mFormatFlags = %u", 264364e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org streamFormat.mFormatFlags); 2644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceInfo, kTraceAudioDevice, _id, "mFormatID", 2645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (const char *) &streamFormat.mFormatID); 2646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2647b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (propertyAddress.mScope == kAudioDevicePropertyScopeInput) 2648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 264964e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org const int io_block_size_samples = streamFormat.mChannelsPerFrame * 265064e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org streamFormat.mSampleRate / 100 * N_BLOCKS_IO; 265164e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org if (io_block_size_samples > _captureBufSizeSamples) 265264e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org { 265364e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 265464e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org "Input IO block size (%d) is larger than ring buffer (%u)", 265564e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org io_block_size_samples, _captureBufSizeSamples); 265664e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org return -1; 265764e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org 265864e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org } 265964e26514dc6e932c6f77753e9357d6f52e771faeandrew@webrtc.org 2660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memcpy(&_inStreamFormat, &streamFormat, sizeof(streamFormat)); 2661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_inStreamFormat.mChannelsPerFrame >= 2 && (_recChannels == 2)) 2663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2664b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mChannelsPerFrame = 2; 2665b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2666b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Disable stereo recording when we only have one channel on the device. 2668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDesiredFormat.mChannelsPerFrame = 1; 2669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _recChannels = 1; 2670b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Stereo recording unavailable on this device"); 2672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2674b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_ptrAudioBuffer) 2675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Update audio buffer with the selected parameters 2677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); 267864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _ptrAudioBuffer->SetRecordingChannels((uint8_t) _recChannels); 2679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Recreate the converter with the new format 2682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(xians): make this thread safe 2683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioConverterDispose(_captureConverter)); 2684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew(&streamFormat, &_inDesiredFormat, 2686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &_captureConverter)); 2687b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2689b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memcpy(&_outStreamFormat, &streamFormat, sizeof(streamFormat)); 2690b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2691b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_outStreamFormat.mChannelsPerFrame >= 2 && (_playChannels == 2)) 2692b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mChannelsPerFrame = 2; 2694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Disable stereo playout when we only have one channel on the device. 2697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _outDesiredFormat.mChannelsPerFrame = 1; 2698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _playChannels = 1; 2699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Stereo playout unavailable on this device"); 2701b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_ptrAudioBuffer) 2704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2705b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Update audio buffer with the selected parameters 2706b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetPlayoutSampleRate(N_PLAY_SAMPLES_PER_SEC); 270764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _ptrAudioBuffer->SetPlayoutChannels((uint8_t) _playChannels); 2708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _renderDelayOffsetSamples = _renderBufSizeSamples - N_BUFFERS_OUT 2711b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * ENGINE_PLAY_BUF_SIZE_IN_SAMPLES 2712b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _outDesiredFormat.mChannelsPerFrame; 2713b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Recreate the converter with the new format 2715b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(xians): make this thread safe 2716b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioConverterDispose(_renderConverter)); 2717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioConverterNew(&_outDesiredFormat, &streamFormat, 2719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &_renderConverter)); 2720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2721b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2723b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 272564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::HandleDataSourceChange( 2726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioObjectID objectId, 2727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioObjectPropertyAddress propertyAddress) 2728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 2730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_macBookPro && propertyAddress.mScope 2732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org == kAudioDevicePropertyScopeOutput) 2733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id, 2735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Data source changed"); 2736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2737b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _macBookProPanRight = false; 2738b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 dataSource = 0; 2739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = sizeof(UInt32); 2740b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(objectId, 2741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &propertyAddress, 0, NULL, &size, &dataSource)); 2742b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (dataSource == 'ispk') 2743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _macBookProPanRight = true; 2745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2746b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "MacBook Pro using internal speakers; stereo panning right"); 2747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2749b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 2750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "MacBook Pro not using internal speakers"); 2751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2752b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 275664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioDeviceMac::HandleProcessorOverload( 2757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioObjectPropertyAddress propertyAddress) 2758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(xians): we probably want to notify the user in some way of the 2760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // overload. However, the Windows interpretations of these errors seem to 2761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // be more severe than what ProcessorOverload is thrown for. 2762b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 2763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We don't log the notification, as it's sent from the HAL's IO thread. We 2764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // don't want to slow it down even further. 2765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (propertyAddress.mScope == kAudioDevicePropertyScopeInput) 2766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org //WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "Capture processor 2768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // overload"); 2769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org //_callback->ProblemIsReported( 2770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // SndCardStreamObserver::ERecordingProblem); 2771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org //WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 2774b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // "Render processor overload"); 2775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org //_callback->ProblemIsReported( 2776b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // SndCardStreamObserver::EPlaybackProblem); 2777b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2778b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2780b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2781b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================ 2783b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Thread Methods 2784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================ 2785b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::deviceIOProc(AudioDeviceID, const AudioTimeStamp*, 2787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioBufferList* inputData, 2788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioTimeStamp* inputTime, 2789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioBufferList* outputData, 2790b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioTimeStamp* outputTime, 2791b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org void *clientData) 2792b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceMac *ptrThis = (AudioDeviceMac *) clientData; 2794b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(ptrThis != NULL); 2795b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ptrThis->implDeviceIOProc(inputData, inputTime, outputData, outputTime); 2797b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2798b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // AudioDeviceIOProc functions are supposed to return 0 2799b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2800b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2802b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::outConverterProc(AudioConverterRef, 2803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 *numberDataPackets, 2804b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioBufferList *data, 2805b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioStreamPacketDescription **, 2806b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org void *userData) 2807b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceMac *ptrThis = (AudioDeviceMac *) userData; 2809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(ptrThis != NULL); 2810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return ptrThis->implOutConverterProc(numberDataPackets, data); 2812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2813b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2814b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::inDeviceIOProc(AudioDeviceID, const AudioTimeStamp*, 2815b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioBufferList* inputData, 2816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioTimeStamp* inputTime, 2817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioBufferList*, 2818b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioTimeStamp*, void* clientData) 2819b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2820b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceMac *ptrThis = (AudioDeviceMac *) clientData; 2821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(ptrThis != NULL); 2822b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2823b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ptrThis->implInDeviceIOProc(inputData, inputTime); 2824b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // AudioDeviceIOProc functions are supposed to return 0 2826b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::inConverterProc( 2830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioConverterRef, 2831b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 *numberDataPackets, 2832b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioBufferList *data, 2833b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioStreamPacketDescription ** /*dataPacketDescription*/, 2834b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org void *userData) 2835b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2836b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioDeviceMac *ptrThis = static_cast<AudioDeviceMac*> (userData); 2837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(ptrThis != NULL); 2838b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2839b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return ptrThis->implInConverterProc(numberDataPackets, data); 2840b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2841b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2842b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::implDeviceIOProc(const AudioBufferList *inputData, 2843b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioTimeStamp *inputTime, 2844b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioBufferList *outputData, 2845b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioTimeStamp *outputTime) 2846b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2847b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 2848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt64 outputTimeNs = AudioConvertHostTimeToNanos(outputTime->mHostTime); 2849b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt64 nowNs = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 2850b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2851b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_twoDevices && _recording) 2852b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2853b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org implInDeviceIOProc(inputData, inputTime); 2854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2855b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2856b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check if we should close down audio device 2857b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Double-checked locking optimization to remove locking overhead 2858b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_doStop) 2859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2860b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Enter(); 2861b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_doStop) 2862b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2863b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_twoDevices || (!_recording && !_playing)) 2864b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2865b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // In the case of a shared device, the single driving ioProc 2866b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // is stopped here 2867b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_ERR(AudioDeviceStop(_outputDeviceID, 2868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _deviceIOProcID)); 2869b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioDeviceDestroyIOProcID(_outputDeviceID, 2870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _deviceIOProcID)); 2871b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err == noErr) 2872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2873b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, 2874b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, " Playout or shared device stopped"); 2875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2877b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2878b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStop = false; 2879b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _stopEvent.Set(); 2880b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); 2881b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2882b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2883b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); 2884b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2885b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2886b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_playing) 2887b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2888b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // This can be the case when a shared device is capturing but not 2889b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // rendering. We allow the checks above before returning to avoid a 2890b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // timeout when capturing is stopped. 2891b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2892b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2893b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2894b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(_outStreamFormat.mBytesPerFrame != 0); 2895b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = outputData->mBuffers->mDataByteSize 2896b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org / _outStreamFormat.mBytesPerFrame; 2897b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(xians): signal an error somehow? 2899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org err = AudioConverterFillComplexBuffer(_renderConverter, outConverterProc, 2900b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org this, &size, outputData, NULL); 2901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err != noErr) 2902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2903b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err == 1) 2904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2905b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // This is our own error. 2906b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 2907b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " Error in AudioConverterFillComplexBuffer()"); 2908b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 1; 2909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 2910b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2911b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, 2912b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Error in AudioConverterFillComplexBuffer()", 2913b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (const char *) &err); 2914b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 1; 2915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2918b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ring_buffer_size_t bufSizeSamples = 2919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PaUtil_GetRingBufferReadAvailable(_paRenderBuffer); 2920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t renderDelayUs = static_cast<int32_t> (1e-3 * (outputTimeNs - nowNs) 2922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org + 0.5); 2923b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org renderDelayUs += static_cast<int32_t> ((1.0e6 * bufSizeSamples) 2924b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org / _outDesiredFormat.mChannelsPerFrame / _outDesiredFormat.mSampleRate 2925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org + 0.5); 2926b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AtomicSet32(&_renderDelayUs, renderDelayUs); 2928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2929b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2931b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::implOutConverterProc(UInt32 *numberDataPackets, 2933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioBufferList *data) 2934b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2935b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(data->mNumberBuffers == 1); 2936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ring_buffer_size_t numSamples = *numberDataPackets 2937b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _outDesiredFormat.mChannelsPerFrame; 2938b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2939b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org data->mBuffers->mNumberChannels = _outDesiredFormat.mChannelsPerFrame; 2940b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Always give the converter as much as it wants, zero padding as required. 2941b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org data->mBuffers->mDataByteSize = *numberDataPackets 2942b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _outDesiredFormat.mBytesPerPacket; 2943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org data->mBuffers->mData = _renderConvertData; 2944b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(_renderConvertData, 0, sizeof(_renderConvertData)); 2945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PaUtil_ReadRingBuffer(_paRenderBuffer, _renderConvertData, numSamples); 2947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kern_return_t kernErr = semaphore_signal_all(_renderSemaphore); 2949b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kernErr != KERN_SUCCESS) 2950b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2951b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 2952b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " semaphore_signal_all() error: %d", kernErr); 2953b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 1; 2954b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2955b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2956b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2957b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 2958b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2959b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::implInDeviceIOProc(const AudioBufferList *inputData, 2960b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const AudioTimeStamp *inputTime) 2961b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 2962b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 2963b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt64 inputTimeNs = AudioConvertHostTimeToNanos(inputTime->mHostTime); 2964b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt64 nowNs = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 2965b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2966b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check if we should close down audio device 2967b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Double-checked locking optimization to remove locking overhead 2968b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_doStopRec) 2969b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2970b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Enter(); 2971b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_doStopRec) 2972b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2973b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // This will be signalled only when a shared device is not in use. 2974b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_ERR(AudioDeviceStop(_inputDeviceID, _inDeviceIOProcID)); 2975b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_CA_LOG_WARN(AudioDeviceDestroyIOProcID(_inputDeviceID, 2976b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _inDeviceIOProcID)); 2977b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err == noErr) 2978b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2979b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, 2980b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, " Recording device stopped"); 2981b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2982b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2983b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _doStopRec = false; 2984b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _stopEventRec.Set(); 2985b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); 2986b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2987b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2988b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _critSect.Leave(); 2989b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2990b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2991b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_recording) 2992b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 2993b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Allow above checks to avoid a timeout on stopping capture. 2994b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 2995b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2996b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2997b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ring_buffer_size_t bufSizeSamples = 2998b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PaUtil_GetRingBufferReadAvailable(_paCaptureBuffer); 2999b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3000b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t captureDelayUs = static_cast<int32_t> (1e-3 * (nowNs - inputTimeNs) 3001b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org + 0.5); 3002b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org captureDelayUs 3003b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org += static_cast<int32_t> ((1.0e6 * bufSizeSamples) 3004b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org / _inStreamFormat.mChannelsPerFrame / _inStreamFormat.mSampleRate 3005b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org + 0.5); 3006b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3007b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AtomicSet32(&_captureDelayUs, captureDelayUs); 3008b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3009b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(inputData->mNumberBuffers == 1); 3010b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ring_buffer_size_t numSamples = inputData->mBuffers->mDataByteSize 3011b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _inStreamFormat.mChannelsPerFrame / _inStreamFormat.mBytesPerPacket; 3012b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PaUtil_WriteRingBuffer(_paCaptureBuffer, inputData->mBuffers->mData, 3013b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org numSamples); 3014b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3015b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kern_return_t kernErr = semaphore_signal_all(_captureSemaphore); 3016b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kernErr != KERN_SUCCESS) 3017b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3018b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 3019b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " semaphore_signal_all() error: %d", kernErr); 3020b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3021b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3022b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return err; 3023b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 3024b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3025b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgOSStatus AudioDeviceMac::implInConverterProc(UInt32 *numberDataPackets, 3026b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioBufferList *data) 3027b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 3028b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org assert(data->mNumberBuffers == 1); 3029b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ring_buffer_size_t numSamples = *numberDataPackets 3030b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _inStreamFormat.mChannelsPerFrame; 3031b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3032b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org while (PaUtil_GetRingBufferReadAvailable(_paCaptureBuffer) < numSamples) 3033b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3034b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org mach_timespec_t timeout; 3035b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org timeout.tv_sec = 0; 3036b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org timeout.tv_nsec = TIMER_PERIOD_MS; 3037b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3038b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kern_return_t kernErr = semaphore_timedwait(_captureSemaphore, timeout); 3039b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kernErr == KERN_OPERATION_TIMED_OUT) 3040b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3041b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t signal = AtomicGet32(&_captureDeviceIsAlive); 3042b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (signal == 0) 3043b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3044b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // The capture device is no longer alive; stop the worker thread. 3045b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *numberDataPackets = 0; 3046b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 1; 3047b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3048b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (kernErr != KERN_SUCCESS) 3049b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3050b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 3051b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " semaphore_wait() error: %d", kernErr); 3052b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3053b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3054b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3055b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Pass the read pointer directly to the converter to avoid a memcpy. 3056b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org void* dummyPtr; 3057b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ring_buffer_size_t dummySize; 3058b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PaUtil_GetRingBufferReadRegions(_paCaptureBuffer, numSamples, 3059b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &data->mBuffers->mData, &numSamples, 3060b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org &dummyPtr, &dummySize); 3061b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PaUtil_AdvanceRingBufferReadIndex(_paCaptureBuffer, numSamples); 3062b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3063b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org data->mBuffers->mNumberChannels = _inStreamFormat.mChannelsPerFrame; 3064b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *numberDataPackets = numSamples / _inStreamFormat.mChannelsPerFrame; 3065b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org data->mBuffers->mDataByteSize = *numberDataPackets 3066b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _inStreamFormat.mBytesPerPacket; 3067b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3068b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 3069b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 3070b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3071b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::RunRender(void* ptrThis) 3072b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 3073b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return static_cast<AudioDeviceMac*> (ptrThis)->RenderWorkerThread(); 3074b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 3075b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3076b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::RenderWorkerThread() 3077b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 3078b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ring_buffer_size_t numSamples = ENGINE_PLAY_BUF_SIZE_IN_SAMPLES 3079b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _outDesiredFormat.mChannelsPerFrame; 3080b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org while (PaUtil_GetRingBufferWriteAvailable(_paRenderBuffer) 3081b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org - _renderDelayOffsetSamples < numSamples) 3082b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3083b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org mach_timespec_t timeout; 3084b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org timeout.tv_sec = 0; 3085b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org timeout.tv_nsec = TIMER_PERIOD_MS; 3086b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3087b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org kern_return_t kernErr = semaphore_timedwait(_renderSemaphore, timeout); 3088b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (kernErr == KERN_OPERATION_TIMED_OUT) 3089b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3090b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t signal = AtomicGet32(&_renderDeviceIsAlive); 3091b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (signal == 0) 3092b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3093b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // The render device is no longer alive; stop the worker thread. 3094b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return false; 3095b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3096b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (kernErr != KERN_SUCCESS) 3097b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3098b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 3099b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " semaphore_timedwait() error: %d", kernErr); 3100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 310364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org int8_t playBuffer[4 * ENGINE_PLAY_BUF_SIZE_IN_SAMPLES]; 3104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_ptrAudioBuffer) 3106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 3108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " capture AudioBuffer is invalid"); 3109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return false; 3110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Ask for new PCM data to be played out using the AudioDeviceBuffer. 311364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t nSamples = 3114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->RequestPlayoutData(ENGINE_PLAY_BUF_SIZE_IN_SAMPLES); 3115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org nSamples = _ptrAudioBuffer->GetPlayoutData(playBuffer); 3117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (nSamples != ENGINE_PLAY_BUF_SIZE_IN_SAMPLES) 3118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 3120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " invalid number of output samples(%d)", nSamples); 3121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 312364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t nOutSamples = nSamples * _outDesiredFormat.mChannelsPerFrame; 3124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SInt16 *pPlayBuffer = (SInt16 *) &playBuffer; 3126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (_macBookProPanRight && (_playChannels == 2)) 3127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Mix entirely into the right channel and zero the left channel. 3129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SInt32 sampleInt32 = 0; 313064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org for (uint32_t sampleIdx = 0; sampleIdx < nOutSamples; sampleIdx 3131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org += 2) 3132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org sampleInt32 = pPlayBuffer[sampleIdx]; 3134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org sampleInt32 += pPlayBuffer[sampleIdx + 1]; 3135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org sampleInt32 /= 2; 3136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (sampleInt32 > 32767) 3138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org sampleInt32 = 32767; 3140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (sampleInt32 < -32768) 3141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org sampleInt32 = -32768; 3143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org pPlayBuffer[sampleIdx] = 0; 3146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org pPlayBuffer[sampleIdx + 1] = static_cast<SInt16> (sampleInt32); 3147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PaUtil_WriteRingBuffer(_paRenderBuffer, pPlayBuffer, nOutSamples); 3151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return true; 3153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 3154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::RunCapture(void* ptrThis) 3156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 3157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return static_cast<AudioDeviceMac*> (ptrThis)->CaptureWorkerThread(); 3158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 3159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioDeviceMac::CaptureWorkerThread() 3161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{ 3162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org OSStatus err = noErr; 3163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 noRecSamples = ENGINE_REC_BUF_SIZE_IN_SAMPLES 3164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * _inDesiredFormat.mChannelsPerFrame; 3165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SInt16 recordBuffer[noRecSamples]; 3166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org UInt32 size = ENGINE_REC_BUF_SIZE_IN_SAMPLES; 3167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org AudioBufferList engineBuffer; 3169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org engineBuffer.mNumberBuffers = 1; // Interleaved channels. 3170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org engineBuffer.mBuffers->mNumberChannels = _inDesiredFormat.mChannelsPerFrame; 3171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org engineBuffer.mBuffers->mDataByteSize = _inDesiredFormat.mBytesPerPacket 3172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * noRecSamples; 3173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org engineBuffer.mBuffers->mData = recordBuffer; 3174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org err = AudioConverterFillComplexBuffer(_captureConverter, inConverterProc, 3176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org this, &size, &engineBuffer, NULL); 3177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err != noErr) 3178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (err == 1) 3180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // This is our own error. 3182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return false; 3183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else 3184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logCAMsg(kTraceError, kTraceAudioDevice, _id, 3186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Error in AudioConverterFillComplexBuffer()", 3187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (const char *) &err); 3188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return false; 3189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(xians): what if the returned size is incorrect? 3193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (size == ENGINE_REC_BUF_SIZE_IN_SAMPLES) 3194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 319564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t currentMicLevel(0); 319664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org uint32_t newMicLevel(0); 319764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org int32_t msecOnPlaySide; 319864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org int32_t msecOnRecordSide; 3199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t captureDelayUs = AtomicGet32(&_captureDelayUs); 3201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int32_t renderDelayUs = AtomicGet32(&_renderDelayUs); 3202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 320364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org msecOnPlaySide = static_cast<int32_t> (1e-3 * (renderDelayUs + 320464a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _renderLatencyUs) + 0.5); 320564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org msecOnRecordSide = static_cast<int32_t> (1e-3 * (captureDelayUs + 320664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _captureLatencyUs) + 320764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org 0.5); 3208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!_ptrAudioBuffer) 3210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 3212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " capture AudioBuffer is invalid"); 3213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return false; 3214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // store the recorded buffer (no action will be taken if the 3217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // #recorded samples is not a full buffer) 321864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org _ptrAudioBuffer->SetRecordedBuffer((int8_t*) &recordBuffer, 321964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org (uint32_t) size); 3220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (AGC()) 3222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // store current mic level in the audio buffer if AGC is enabled 3224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (MicrophoneVolume(currentMicLevel) == 0) 3225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // this call does not affect the actual microphone volume 3227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetCurrentMicLevel(currentMicLevel); 3228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->SetVQEData(msecOnPlaySide, msecOnRecordSide, 0); 3232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 323328832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org _ptrAudioBuffer->SetTypingStatus(KeyPressed()); 323428832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org 3235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // deliver recorded samples at specified sample rate, mic level etc. 3236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // to the observer using callback 3237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _ptrAudioBuffer->DeliverRecordedData(); 3238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (AGC()) 3240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org newMicLevel = _ptrAudioBuffer->NewMicLevel(); 3242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (newMicLevel != 0) 3243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // The VQE will only deliver non-zero microphone levels when 3245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // a change is needed. 3246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Set this new mic level (received from the observer as return 3247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // value in the callback). 3248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, 3249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org _id, " AGC change of volume: old=%u => new=%u", 3250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org currentMicLevel, newMicLevel); 3251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (SetMicrophoneVolume(newMicLevel) == -1) 3252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org { 3253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 3254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org " the required modification of the microphone " 3255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "volume failed"); 3256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 3260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return true; 3262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 3263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3264e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.orgbool AudioDeviceMac::KeyPressed() { 326528832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org bool key_down = false; 3266e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org // Loop through all Mac virtual key constant values. 3267e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org for (unsigned int key_index = 0; 3268e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org key_index < ARRAY_SIZE(prev_key_state_); 3269e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org ++key_index) { 3270e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org bool keyState = CGEventSourceKeyState( 3271e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org kCGEventSourceStateHIDSystemState, 3272e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org key_index); 3273e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org // A false -> true change in keymap means a key is pressed. 3274e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org key_down |= (keyState && !prev_key_state_[key_index]); 3275e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org // Save current state. 3276e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org prev_key_state_[key_index] = keyState; 327728832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org } 3278e807da90b76f8ebfed6037fc55c25c25b196a331niklas.enbom@webrtc.org return key_down; 327928832e1965ca0c22ca6a26bbd3387db4db640bedniklas.enbom@webrtc.org} 32803b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org} // namespace webrtc 3281