diff --git a/EchoCanceller.cpp b/EchoCanceller.cpp index 2ce1410b4f..2106532d2b 100644 --- a/EchoCanceller.cpp +++ b/EchoCanceller.cpp @@ -86,7 +86,7 @@ EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ //#ifndef TGVOIP_USE_DESKTOP_DSP ns=WebRtcNsx_Create(); WebRtcNsx_Init((NsxHandle*)ns, 48000); - WebRtcNsx_set_policy((NsxHandle*)ns, 2); + WebRtcNsx_set_policy((NsxHandle*)ns, 1); /*#else ns=WebRtcNs_Create(); WebRtcNs_Init((NsHandle*)ns, 48000); @@ -99,19 +99,11 @@ EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ WebRtcAgcConfig agcConfig; agcConfig.compressionGaindB = 9; agcConfig.limiterEnable = 1; -#ifndef TGVOIP_USE_DESKTOP_DSP agcConfig.targetLevelDbfs = 3; -#else - agcConfig.targetLevelDbfs = 9; -#endif WebRtcAgc_Init(agc, 0, 255, kAgcModeAdaptiveAnalog, 48000); WebRtcAgc_set_config(agc, agcConfig); agcMicLevel=128; } - - /*state=webrtc::WebRtcAec_Create(); - webrtc::WebRtcAec_Init(state, 16000, 16000); - webrtc::WebRtcAec_enable_delay_agnostic(webrtc::WebRtcAec_aec_core(state), 1);*/ #endif } @@ -224,29 +216,6 @@ void EchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_t memcpy(bufIn->ibuf()->bands(0)[0], samplesIn, 960*2); ((webrtc::SplittingFilter*)splittingFilter)->Analysis(bufIn, bufOut); - - if(enableAGC){ - int16_t _agcOut[3][320]; - int16_t* agcIn[3]; - int16_t* agcOut[3]; - for(i=0;i<3;i++){ - agcIn[i]=(int16_t*)bufOut->ibuf_const()->bands(0)[i]; - agcOut[i]=_agcOut[i]; - } - uint8_t saturation; - WebRtcAgc_AddMic(agc, agcIn, 3, 160); - WebRtcAgc_Process(agc, (const int16_t *const *) agcIn, 3, 160, agcOut, agcMicLevel, &agcMicLevel, 0, &saturation); - for(i=0;i<3;i++){ - agcOut[i]+=160; - agcIn[i]+=160; - } - WebRtcAgc_AddMic(agc, agcIn, 3, 160); - WebRtcAgc_Process(agc, (const int16_t *const *) agcIn, 3, 160, agcOut, agcMicLevel, &agcMicLevel, 0, &saturation); - //LOGV("AGC mic level %d", agcMicLevel); - memcpy(bufOut->ibuf()->bands(0)[0], _agcOut[0], 320*2); - memcpy(bufOut->ibuf()->bands(0)[1], _agcOut[1], 320*2); - memcpy(bufOut->ibuf()->bands(0)[2], _agcOut[2], 320*2); - } #ifndef TGVOIP_USE_DESKTOP_DSP if(enableAEC && enableNS){ @@ -356,6 +325,29 @@ void EchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_t memcpy(bufOut->fbuf()->bands(0)[2], _aecOut[2], 320*4); } #endif + + if(enableAGC){ + int16_t _agcOut[3][320]; + int16_t* agcIn[3]; + int16_t* agcOut[3]; + for(i=0;i<3;i++){ + agcIn[i]=(int16_t*)bufOut->ibuf_const()->bands(0)[i]; + agcOut[i]=_agcOut[i]; + } + uint8_t saturation; + WebRtcAgc_AddMic(agc, agcIn, 3, 160); + WebRtcAgc_Process(agc, (const int16_t *const *) agcIn, 3, 160, agcOut, agcMicLevel, &agcMicLevel, 0, &saturation); + for(i=0;i<3;i++){ + agcOut[i]+=160; + agcIn[i]+=160; + } + WebRtcAgc_AddMic(agc, agcIn, 3, 160); + WebRtcAgc_Process(agc, (const int16_t *const *) agcIn, 3, 160, agcOut, agcMicLevel, &agcMicLevel, 0, &saturation); + //LOGV("AGC mic level %d", agcMicLevel); + memcpy(bufOut->ibuf()->bands(0)[0], _agcOut[0], 320*2); + memcpy(bufOut->ibuf()->bands(0)[1], _agcOut[1], 320*2); + memcpy(bufOut->ibuf()->bands(0)[2], _agcOut[2], 320*2); + } ((webrtc::SplittingFilter*)splittingFilter)->Synthesis(bufOut, bufIn); diff --git a/audio/AudioInput.cpp b/audio/AudioInput.cpp index 674b955119..cc552abbb5 100644 --- a/audio/AudioInput.cpp +++ b/audio/AudioInput.cpp @@ -10,9 +10,8 @@ #include "../os/android/AudioInputAndroid.h" #elif defined(__APPLE__) #include -#if TARGET_OS_IPHONE #include "../os/darwin/AudioInputAudioUnit.h" -#else +#if TARGET_OS_OSX #include "../os/darwin/AudioInputAudioUnitOSX.h" #endif #elif defined(_WIN32) @@ -45,10 +44,10 @@ AudioInput *AudioInput::Create(std::string deviceID){ return new AudioInputAndroid(); #elif defined(__APPLE__) #if TARGET_OS_OSX - return new AudioInputAudioUnit(deviceID); -#else - return new AudioInputAudioUnit(); + if(kCFCoreFoundationVersionNumber& devs){ #if defined(__APPLE__) && TARGET_OS_OSX - AudioInputAudioUnit::EnumerateDevices(devs); + AudioInputAudioUnitLegacy::EnumerateDevices(devs); #elif defined(_WIN32) #ifdef TGVOIP_WINXP_COMPAT if(LOBYTE(LOWORD(GetVersion()))<6){ diff --git a/audio/AudioOutput.cpp b/audio/AudioOutput.cpp index 4f5fdfa15e..3e3dbd7afe 100644 --- a/audio/AudioOutput.cpp +++ b/audio/AudioOutput.cpp @@ -11,9 +11,8 @@ #include "../os/android/AudioOutputAndroid.h" #elif defined(__APPLE__) #include -#if TARGET_OS_IPHONE #include "../os/darwin/AudioOutputAudioUnit.h" -#else +#if TARGET_OS_OSX #include "../os/darwin/AudioOutputAudioUnitOSX.h" #endif #elif defined(_WIN32) @@ -43,10 +42,10 @@ AudioOutput *AudioOutput::Create(std::string deviceID){ return new AudioOutputOpenSLES(); #elif defined(__APPLE__) #if TARGET_OS_OSX - return new AudioOutputAudioUnit(deviceID); -#else - return new AudioOutputAudioUnit(); + if(kCFCoreFoundationVersionNumber& devs){ #if defined(__APPLE__) && TARGET_OS_OSX - AudioOutputAudioUnit::EnumerateDevices(devs); + AudioOutputAudioUnitLegacy::EnumerateDevices(devs); #elif defined(_WIN32) #ifdef TGVOIP_WINXP_COMPAT if(LOBYTE(LOWORD(GetVersion()))<6){ diff --git a/libtgvoip.gyp b/libtgvoip.gyp index 52fbea1db6..527708d96b 100644 --- a/libtgvoip.gyp +++ b/libtgvoip.gyp @@ -75,10 +75,16 @@ '<(tgvoip_src_loc)/os/windows/AudioInputWASAPI.h', # macOS + '<(tgvoip_src_loc)/os/darwin/AudioInputAudioUnit.cpp', + '<(tgvoip_src_loc)/os/darwin/AudioInputAudioUnit.h', + '<(tgvoip_src_loc)/os/darwin/AudioOutputAudioUnit.cpp', + '<(tgvoip_src_loc)/os/darwin/AudioOutputAudioUnit.h', '<(tgvoip_src_loc)/os/darwin/AudioInputAudioUnitOSX.cpp', '<(tgvoip_src_loc)/os/darwin/AudioInputAudioUnitOSX.h', '<(tgvoip_src_loc)/os/darwin/AudioOutputAudioUnitOSX.cpp', '<(tgvoip_src_loc)/os/darwin/AudioOutputAudioUnitOSX.h', + '<(tgvoip_src_loc)/os/darwin/AudioUnitIO.cpp', + '<(tgvoip_src_loc)/os/darwin/AudioUnitIO.h', '<(tgvoip_src_loc)/os/darwin/DarwinSpecific.mm', '<(tgvoip_src_loc)/os/darwin/DarwinSpecific.h', diff --git a/os/darwin/AudioInputAudioUnit.cpp b/os/darwin/AudioInputAudioUnit.cpp index 265f0d3de7..decd086056 100644 --- a/os/darwin/AudioInputAudioUnit.cpp +++ b/os/darwin/AudioInputAudioUnit.cpp @@ -16,11 +16,15 @@ using namespace tgvoip; using namespace tgvoip::audio; -AudioInputAudioUnit::AudioInputAudioUnit(){ +AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID){ remainingDataSize=0; isRecording=false; this->io=AudioUnitIO::Get(); +#if TARGET_OS_OSX + io->SetCurrentDevice(true, deviceID); +#endif io->AttachInput(this); + failed=io->IsFailed(); } AudioInputAudioUnit::~AudioInputAudioUnit(){ @@ -35,6 +39,7 @@ void AudioInputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, void AudioInputAudioUnit::Start(){ isRecording=true; io->EnableInput(true); + failed=io->IsFailed(); } void AudioInputAudioUnit::Stop(){ @@ -44,11 +49,22 @@ void AudioInputAudioUnit::Stop(){ void AudioInputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ int i; + int j; for(i=0;imNumberBuffers;i++){ AudioBuffer buf=ioData->mBuffers[i]; +#if TARGET_OS_OSX + assert(remainingDataSize+buf.mDataByteSize/2<10240); + float* src=reinterpret_cast(buf.mData); + int16_t* dst=reinterpret_cast(remainingData+remainingDataSize); + for(j=0;j=BUFFER_SIZE*2){ InvokeCallback((unsigned char*)remainingData, BUFFER_SIZE*2); remainingDataSize-=BUFFER_SIZE*2; @@ -58,3 +74,9 @@ void AudioInputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ } } } + +#if TARGET_OS_OSX +void AudioInputAudioUnit::SetCurrentDevice(std::string deviceID){ + io->SetCurrentDevice(true, deviceID); +} +#endif diff --git a/os/darwin/AudioInputAudioUnit.h b/os/darwin/AudioInputAudioUnit.h index 97ea051e14..e66a80b24a 100644 --- a/os/darwin/AudioInputAudioUnit.h +++ b/os/darwin/AudioInputAudioUnit.h @@ -16,12 +16,15 @@ class AudioUnitIO; class AudioInputAudioUnit : public AudioInput{ public: - AudioInputAudioUnit(); + AudioInputAudioUnit(std::string deviceID); virtual ~AudioInputAudioUnit(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); void HandleBufferCallback(AudioBufferList* ioData); +#if TARGET_OS_OSX + virtual void SetCurrentDevice(std::string deviceID); +#endif private: unsigned char remainingData[10240]; diff --git a/os/darwin/AudioInputAudioUnitOSX.cpp b/os/darwin/AudioInputAudioUnitOSX.cpp index 6078327f7a..149dc90566 100644 --- a/os/darwin/AudioInputAudioUnitOSX.cpp +++ b/os/darwin/AudioInputAudioUnitOSX.cpp @@ -20,13 +20,13 @@ using namespace tgvoip; using namespace tgvoip::audio; -AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID) : AudioInput(deviceID){ +AudioInputAudioUnitLegacy::AudioInputAudioUnitLegacy(std::string deviceID) : AudioInput(deviceID){ remainingDataSize=0; isRecording=false; OSStatus status; AudioComponentDescription inputDesc={ - .componentType = kAudioUnitType_Output, .componentSubType = kAudioUnitSubType_HALOutput, .componentFlags = 0, .componentFlagsMask = 0, + .componentType = kAudioUnitType_Output, .componentSubType = /*kAudioUnitSubType_HALOutput*/kAudioUnitSubType_VoiceProcessingIO, .componentFlags = 0, .componentFlagsMask = 0, .componentManufacturer = kAudioUnitManufacturer_Apple }; AudioComponent component=AudioComponentFindNext(NULL, &inputDesc); @@ -51,10 +51,10 @@ AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID) : AudioInput(devi propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; - AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioInputAudioUnit::DefaultDeviceChangedCallback, this); + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioInputAudioUnitLegacy::DefaultDeviceChangedCallback, this); AURenderCallbackStruct callbackStruct; - callbackStruct.inputProc = AudioInputAudioUnit::BufferCallback; + callbackStruct.inputProc = AudioInputAudioUnitLegacy::BufferCallback; callbackStruct.inputProcRefCon=this; status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callbackStruct, sizeof(callbackStruct)); CHECK_AU_ERROR(status, "Error setting input buffer callback"); @@ -66,42 +66,42 @@ AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID) : AudioInput(devi inBufferList.mNumberBuffers=1; } -AudioInputAudioUnit::~AudioInputAudioUnit(){ +AudioInputAudioUnitLegacy::~AudioInputAudioUnitLegacy(){ AudioObjectPropertyAddress propertyAddress; propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; - AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioInputAudioUnit::DefaultDeviceChangedCallback, this); + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioInputAudioUnitLegacy::DefaultDeviceChangedCallback, this); AudioUnitUninitialize(unit); AudioComponentInstanceDispose(unit); free(inBufferList.mBuffers[0].mData); } -void AudioInputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioInputAudioUnitLegacy::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ } -void AudioInputAudioUnit::Start(){ +void AudioInputAudioUnitLegacy::Start(){ isRecording=true; OSStatus status=AudioOutputUnitStart(unit); CHECK_AU_ERROR(status, "Error starting AudioUnit"); } -void AudioInputAudioUnit::Stop(){ +void AudioInputAudioUnitLegacy::Stop(){ isRecording=false; OSStatus status=AudioOutputUnitStart(unit); CHECK_AU_ERROR(status, "Error stopping AudioUnit"); } -OSStatus AudioInputAudioUnit::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ - AudioInputAudioUnit* input=(AudioInputAudioUnit*) inRefCon; +OSStatus AudioInputAudioUnitLegacy::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ + AudioInputAudioUnitLegacy* input=(AudioInputAudioUnitLegacy*) inRefCon; input->inBufferList.mBuffers[0].mDataByteSize=10240; OSStatus res=AudioUnitRender(input->unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &input->inBufferList); input->HandleBufferCallback(&input->inBufferList); return noErr; } -void AudioInputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ +void AudioInputAudioUnitLegacy::HandleBufferCallback(AudioBufferList *ioData){ int i; for(i=0;imNumberBuffers;i++){ AudioBuffer buf=ioData->mBuffers[i]; @@ -124,7 +124,7 @@ void AudioInputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ } -void AudioInputAudioUnit::EnumerateDevices(std::vector& devs){ +void AudioInputAudioUnitLegacy::EnumerateDevices(std::vector& devs){ AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, @@ -211,7 +211,7 @@ void AudioInputAudioUnit::EnumerateDevices(std::vector& devs){ audioDevices = NULL; } -void AudioInputAudioUnit::SetCurrentDevice(std::string deviceID){ +void AudioInputAudioUnitLegacy::SetCurrentDevice(std::string deviceID){ UInt32 size=sizeof(AudioDeviceID); AudioDeviceID inputDevice=NULL; OSStatus status; @@ -299,9 +299,9 @@ void AudioInputAudioUnit::SetCurrentDevice(std::string deviceID){ } } -OSStatus AudioInputAudioUnit::DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData){ +OSStatus AudioInputAudioUnitLegacy::DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData){ LOGV("System default input device changed"); - AudioInputAudioUnit* self=(AudioInputAudioUnit*)inClientData; + AudioInputAudioUnitLegacy* self=(AudioInputAudioUnitLegacy*)inClientData; if(self->currentDevice=="default"){ self->SetCurrentDevice(self->currentDevice); } diff --git a/os/darwin/AudioInputAudioUnitOSX.h b/os/darwin/AudioInputAudioUnitOSX.h index db6c2db79a..cd0f3c6313 100644 --- a/os/darwin/AudioInputAudioUnitOSX.h +++ b/os/darwin/AudioInputAudioUnitOSX.h @@ -4,8 +4,8 @@ // you should have received with this source code distribution. // -#ifndef LIBTGVOIP_AUDIOINPUTAUDIOUNIT_H -#define LIBTGVOIP_AUDIOINPUTAUDIOUNIT_H +#ifndef LIBTGVOIP_AUDIOINPUTAUDIOUNIT_OSX_H +#define LIBTGVOIP_AUDIOINPUTAUDIOUNIT_OSX_H #include #import @@ -13,11 +13,11 @@ #include "../../audio/AudioInput.h" namespace tgvoip{ namespace audio{ -class AudioInputAudioUnit : public AudioInput{ +class AudioInputAudioUnitLegacy : public AudioInput{ public: - AudioInputAudioUnit(std::string deviceID); - virtual ~AudioInputAudioUnit(); + AudioInputAudioUnitLegacy(std::string deviceID); + virtual ~AudioInputAudioUnitLegacy(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); @@ -37,4 +37,4 @@ private: }; }} -#endif //LIBTGVOIP_AUDIOINPUTAUDIOUNIT_H +#endif //LIBTGVOIP_AUDIOINPUTAUDIOUNIT_OSX_H diff --git a/os/darwin/AudioOutputAudioUnit.cpp b/os/darwin/AudioOutputAudioUnit.cpp index 9bc06ae8dd..7114d4dbfe 100644 --- a/os/darwin/AudioOutputAudioUnit.cpp +++ b/os/darwin/AudioOutputAudioUnit.cpp @@ -17,12 +17,16 @@ const int8_t permutation[33]={0,1,2,3,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,9,9,9, using namespace tgvoip; using namespace tgvoip::audio; -AudioOutputAudioUnit::AudioOutputAudioUnit(){ +AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){ isPlaying=false; remainingDataSize=0; level=0.0; this->io=AudioUnitIO::Get(); +#if TARGET_OS_OSX + io->SetCurrentDevice(false, deviceID); +#endif io->AttachOutput(this); + failed=io->IsFailed(); } AudioOutputAudioUnit::~AudioOutputAudioUnit(){ @@ -45,6 +49,7 @@ void AudioOutputAudioUnit::EnableLoudspeaker(bool enabled){ void AudioOutputAudioUnit::Start(){ isPlaying=true; io->EnableOutput(true); + failed=io->IsFailed(); } void AudioOutputAudioUnit::Stop(){ @@ -75,11 +80,21 @@ void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ InvokeCallback(remainingData+remainingDataSize, BUFFER_SIZE*2); remainingDataSize+=BUFFER_SIZE*2; } +#if TARGET_OS_OSX + float* dst=reinterpret_cast(buf.mData); + int16_t* src=reinterpret_cast(remainingData); + for(k=0;kabsVal) @@ -99,7 +114,12 @@ void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ } level=permutation[position]; absMax>>=2; - } + }*/ } } +#if TARGET_OS_OSX +void AudioOutputAudioUnit::SetCurrentDevice(std::string deviceID){ + io->SetCurrentDevice(false, deviceID); +} +#endif diff --git a/os/darwin/AudioOutputAudioUnit.h b/os/darwin/AudioOutputAudioUnit.h index ba591aec6e..18561b6a15 100644 --- a/os/darwin/AudioOutputAudioUnit.h +++ b/os/darwin/AudioOutputAudioUnit.h @@ -15,7 +15,7 @@ class AudioUnitIO; class AudioOutputAudioUnit : public AudioOutput{ public: - AudioOutputAudioUnit(); + AudioOutputAudioUnit(std::string deviceID); virtual ~AudioOutputAudioUnit(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual bool IsPhone(); @@ -25,6 +25,9 @@ public: virtual bool IsPlaying(); virtual float GetLevel(); void HandleBufferCallback(AudioBufferList* ioData); +#if TARGET_OS_OSX + virtual void SetCurrentDevice(std::string deviceID); +#endif private: bool isPlaying; diff --git a/os/darwin/AudioOutputAudioUnitOSX.cpp b/os/darwin/AudioOutputAudioUnitOSX.cpp index d46e7f5ba3..49c9662d4b 100644 --- a/os/darwin/AudioOutputAudioUnitOSX.cpp +++ b/os/darwin/AudioOutputAudioUnitOSX.cpp @@ -20,7 +20,7 @@ using namespace tgvoip; using namespace tgvoip::audio; -AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){ +AudioOutputAudioUnitLegacy::AudioOutputAudioUnitLegacy(std::string deviceID){ remainingDataSize=0; isPlaying=false; sysDevID=NULL; @@ -61,7 +61,7 @@ AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){ propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; - AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioOutputAudioUnit::DefaultDeviceChangedCallback, this); + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioOutputAudioUnitLegacy::DefaultDeviceChangedCallback, this); AudioStreamBasicDescription desiredFormat={ .mSampleRate=/*hardwareFormat.mSampleRate*/48000, .mFormatID=kAudioFormatLinearPCM, .mFormatFlags=kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian, @@ -72,7 +72,7 @@ AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){ CHECK_AU_ERROR(status, "Error setting format"); AURenderCallbackStruct callbackStruct; - callbackStruct.inputProc = AudioOutputAudioUnit::BufferCallback; + callbackStruct.inputProc = AudioOutputAudioUnitLegacy::BufferCallback; callbackStruct.inputProcRefCon=this; status = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &callbackStruct, sizeof(callbackStruct)); CHECK_AU_ERROR(status, "Error setting input buffer callback"); @@ -80,12 +80,12 @@ AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){ CHECK_AU_ERROR(status, "Error initializing unit"); } -AudioOutputAudioUnit::~AudioOutputAudioUnit(){ +AudioOutputAudioUnitLegacy::~AudioOutputAudioUnitLegacy(){ AudioObjectPropertyAddress propertyAddress; propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; - AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioOutputAudioUnit::DefaultDeviceChangedCallback, this); + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioOutputAudioUnitLegacy::DefaultDeviceChangedCallback, this); AudioObjectPropertyAddress dataSourceProp={ kAudioDevicePropertyDataSource, @@ -93,39 +93,39 @@ AudioOutputAudioUnit::~AudioOutputAudioUnit(){ kAudioObjectPropertyElementMaster }; if(isMacBookPro && sysDevID && AudioObjectHasProperty(sysDevID, &dataSourceProp)){ - AudioObjectRemovePropertyListener(sysDevID, &dataSourceProp, AudioOutputAudioUnit::DefaultDeviceChangedCallback, this); + AudioObjectRemovePropertyListener(sysDevID, &dataSourceProp, AudioOutputAudioUnitLegacy::DefaultDeviceChangedCallback, this); } AudioUnitUninitialize(unit); AudioComponentInstanceDispose(unit); } -void AudioOutputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ +void AudioOutputAudioUnitLegacy::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ } -void AudioOutputAudioUnit::Start(){ +void AudioOutputAudioUnitLegacy::Start(){ isPlaying=true; OSStatus status=AudioOutputUnitStart(unit); CHECK_AU_ERROR(status, "Error starting AudioUnit"); } -void AudioOutputAudioUnit::Stop(){ +void AudioOutputAudioUnitLegacy::Stop(){ isPlaying=false; OSStatus status=AudioOutputUnitStart(unit); CHECK_AU_ERROR(status, "Error stopping AudioUnit"); } -OSStatus AudioOutputAudioUnit::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ - AudioOutputAudioUnit* input=(AudioOutputAudioUnit*) inRefCon; +OSStatus AudioOutputAudioUnitLegacy::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ + AudioOutputAudioUnitLegacy* input=(AudioOutputAudioUnitLegacy*) inRefCon; input->HandleBufferCallback(ioData); return noErr; } -bool AudioOutputAudioUnit::IsPlaying(){ +bool AudioOutputAudioUnitLegacy::IsPlaying(){ return isPlaying; } -void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ +void AudioOutputAudioUnitLegacy::HandleBufferCallback(AudioBufferList *ioData){ int i; unsigned int k; int16_t absVal=0; @@ -147,7 +147,7 @@ void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){ } -void AudioOutputAudioUnit::EnumerateDevices(std::vector& devs){ +void AudioOutputAudioUnitLegacy::EnumerateDevices(std::vector& devs){ AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, @@ -234,7 +234,7 @@ void AudioOutputAudioUnit::EnumerateDevices(std::vector& devs audioDevices = NULL; } -void AudioOutputAudioUnit::SetCurrentDevice(std::string deviceID){ +void AudioOutputAudioUnitLegacy::SetCurrentDevice(std::string deviceID){ UInt32 size=sizeof(AudioDeviceID); AudioDeviceID outputDevice=NULL; OSStatus status; @@ -245,7 +245,7 @@ void AudioOutputAudioUnit::SetCurrentDevice(std::string deviceID){ }; if(isMacBookPro && sysDevID && AudioObjectHasProperty(sysDevID, &dataSourceProp)){ - AudioObjectRemovePropertyListener(sysDevID, &dataSourceProp, AudioOutputAudioUnit::DefaultDeviceChangedCallback, this); + AudioObjectRemovePropertyListener(sysDevID, &dataSourceProp, AudioOutputAudioUnitLegacy::DefaultDeviceChangedCallback, this); } if(deviceID=="default"){ @@ -337,22 +337,22 @@ void AudioOutputAudioUnit::SetCurrentDevice(std::string deviceID){ size=4; AudioObjectGetPropertyData(outputDevice, &dataSourceProp, 0, NULL, &size, &dataSource); SetPanRight(dataSource=='ispk'); - AudioObjectAddPropertyListener(outputDevice, &dataSourceProp, AudioOutputAudioUnit::DefaultDeviceChangedCallback, this); + AudioObjectAddPropertyListener(outputDevice, &dataSourceProp, AudioOutputAudioUnitLegacy::DefaultDeviceChangedCallback, this); }else{ SetPanRight(false); } } } -void AudioOutputAudioUnit::SetPanRight(bool panRight){ +void AudioOutputAudioUnitLegacy::SetPanRight(bool panRight){ LOGI("%sabling pan right on macbook pro", panRight ? "En" : "Dis"); int32_t channelMap[]={panRight ? -1 : 0, 0}; OSStatus status=AudioUnitSetProperty(unit, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Global, kOutputBus, channelMap, sizeof(channelMap)); CHECK_AU_ERROR(status, "Error setting channel map"); } -OSStatus AudioOutputAudioUnit::DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData){ - AudioOutputAudioUnit* self=(AudioOutputAudioUnit*)inClientData; +OSStatus AudioOutputAudioUnitLegacy::DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData){ + AudioOutputAudioUnitLegacy* self=(AudioOutputAudioUnitLegacy*)inClientData; if(inAddresses[0].mSelector==kAudioHardwarePropertyDefaultOutputDevice){ LOGV("System default input device changed"); if(self->currentDevice=="default"){ diff --git a/os/darwin/AudioOutputAudioUnitOSX.h b/os/darwin/AudioOutputAudioUnitOSX.h index 91fb2d4a90..d73bb5412c 100644 --- a/os/darwin/AudioOutputAudioUnitOSX.h +++ b/os/darwin/AudioOutputAudioUnitOSX.h @@ -4,8 +4,8 @@ // you should have received with this source code distribution. // -#ifndef LIBTGVOIP_AUDIOINPUTAUDIOUNIT_H -#define LIBTGVOIP_AUDIOINPUTAUDIOUNIT_H +#ifndef LIBTGVOIP_AUDIOINPUTAUDIOUNIT_OSX_H +#define LIBTGVOIP_AUDIOINPUTAUDIOUNIT_OSX_H #include #import @@ -13,11 +13,11 @@ #include "../../audio/AudioOutput.h" namespace tgvoip{ namespace audio{ -class AudioOutputAudioUnit : public AudioOutput{ +class AudioOutputAudioUnitLegacy : public AudioOutput{ public: - AudioOutputAudioUnit(std::string deviceID); - virtual ~AudioOutputAudioUnit(); + AudioOutputAudioUnitLegacy(std::string deviceID); + virtual ~AudioOutputAudioUnitLegacy(); virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); virtual void Start(); virtual void Stop(); @@ -40,4 +40,4 @@ private: }; }} -#endif //LIBTGVOIP_AUDIOINPUTAUDIOUNIT_H +#endif //LIBTGVOIP_AUDIOINPUTAUDIOUNIT_OSX_H diff --git a/os/darwin/AudioUnitIO.cpp b/os/darwin/AudioUnitIO.cpp index 1da244b6de..69a924f99e 100644 --- a/os/darwin/AudioUnitIO.cpp +++ b/os/darwin/AudioUnitIO.cpp @@ -4,7 +4,6 @@ // you should have received with this source code distribution. // #include -#include #include "AudioUnitIO.h" #include "AudioInputAudioUnit.h" #include "AudioOutputAudioUnit.h" @@ -12,7 +11,7 @@ #include "../../VoIPController.h" #include "../../VoIPServerConfig.h" -#define CHECK_AU_ERROR(res, msg) if(res!=noErr){ LOGE(msg": OSStatus=%d", (int)res); return; } +#define CHECK_AU_ERROR(res, msg) if(res!=noErr){ LOGE(msg": OSStatus=%d", (int)res); failed=true; return; } #define BUFFER_SIZE 960 // 20 ms #define kOutputBus 0 @@ -23,57 +22,106 @@ using namespace tgvoip::audio; int AudioUnitIO::refCount=0; AudioUnitIO* AudioUnitIO::sharedInstance=NULL; -bool AudioUnitIO::haveAudioSession=false; AudioUnitIO::AudioUnitIO(){ input=NULL; output=NULL; - configured=false; inputEnabled=false; outputEnabled=false; + failed=false; + started=false; inBufferList.mBuffers[0].mData=malloc(10240); inBufferList.mBuffers[0].mDataByteSize=10240; inBufferList.mNumberBuffers=1; -#ifdef TGVOIP_USE_AUDIO_SESSION - if(haveAudioSession) - ProcessAudioSessionAcquired(); -#else - haveAudioSession=true; - ProcessAudioSessionAcquired(); -#endif -} - -AudioUnitIO::~AudioUnitIO(){ - if(runFakeIO){ - runFakeIO=false; - join_thread(fakeIOThread); - } - AudioOutputUnitStop(unit); - AudioUnitUninitialize(unit); - AudioComponentInstanceDispose(unit); - free(inBufferList.mBuffers[0].mData); - haveAudioSession=false; -} - -void AudioUnitIO::ProcessAudioSessionAcquired(){ + OSStatus status; AudioComponentDescription desc; AudioComponent inputComponent; desc.componentType = kAudioUnitType_Output; -#if TARGET_OS_IPHONE - //desc.componentSubType = kAudioUnitSubType_RemoteIO; desc.componentSubType = kAudioUnitSubType_VoiceProcessingIO; -#else - desc.componentSubType = kAudioUnitSubType_HALOutput; -#endif desc.componentFlags = 0; desc.componentFlagsMask = 0; desc.componentManufacturer = kAudioUnitManufacturer_Apple; inputComponent = AudioComponentFindNext(NULL, &desc); status = AudioComponentInstanceNew(inputComponent, &unit); - if(configured) - ActuallyConfigure(cfgSampleRate, cfgBitsPerSample, cfgChannels); + UInt32 flag=1; +#if TARGET_OS_IPHONE + status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag)); + CHECK_AU_ERROR(status, "Error enabling AudioUnit output"); + status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); + CHECK_AU_ERROR(status, "Error enabling AudioUnit input"); +#endif + +#if TARGET_OS_IPHONE + flag=ServerConfig::GetSharedInstance()->GetBoolean("use_ios_vpio_agc", true) ? 1 : 0; +#else + flag=ServerConfig::GetSharedInstance()->GetBoolean("use_osx_vpio_agc", true) ? 1 : 0; +#endif + status=AudioUnitSetProperty(unit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, kAudioUnitScope_Global, kInputBus, &flag, sizeof(flag)); + CHECK_AU_ERROR(status, "Error disabling AGC"); + + AudioStreamBasicDescription audioFormat; + audioFormat.mSampleRate = 48000; + audioFormat.mFormatID = kAudioFormatLinearPCM; +#if TARGET_OS_IPHONE + audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian; + audioFormat.mBitsPerChannel = 16; + audioFormat.mBytesPerPacket = 2; + audioFormat.mBytesPerFrame = 2; +#else // OS X + audioFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian; + audioFormat.mBitsPerChannel = 32; + audioFormat.mBytesPerPacket = 4; + audioFormat.mBytesPerFrame = 4; +#endif + audioFormat.mFramesPerPacket = 1; + audioFormat.mChannelsPerFrame = 1; + + status = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &audioFormat, sizeof(audioFormat)); + CHECK_AU_ERROR(status, "Error setting output format"); + status = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &audioFormat, sizeof(audioFormat)); + CHECK_AU_ERROR(status, "Error setting input format"); + + AURenderCallbackStruct callbackStruct; + + callbackStruct.inputProc = AudioUnitIO::BufferCallback; + callbackStruct.inputProcRefCon = this; + status = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &callbackStruct, sizeof(callbackStruct)); + CHECK_AU_ERROR(status, "Error setting output buffer callback"); + status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callbackStruct, sizeof(callbackStruct)); + CHECK_AU_ERROR(status, "Error setting input buffer callback"); + +#if TARGET_OS_OSX + CFRunLoopRef theRunLoop = NULL; + AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyRunLoop, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + status = AudioObjectSetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); + + propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioUnitIO::DefaultDeviceChangedCallback, this); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioUnitIO::DefaultDeviceChangedCallback, this); +#endif +} + +AudioUnitIO::~AudioUnitIO(){ + AudioOutputUnitStop(unit); + AudioUnitUninitialize(unit); + AudioComponentInstanceDispose(unit); + free(inBufferList.mBuffers[0].mData); +#if TARGET_OS_OSX + AudioObjectPropertyAddress propertyAddress; + propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioUnitIO::DefaultDeviceChangedCallback, this); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioUnitIO::DefaultDeviceChangedCallback, this); +#endif } AudioUnitIO* AudioUnitIO::Get(){ @@ -94,72 +142,8 @@ void AudioUnitIO::Release(){ } } -void AudioUnitIO::AudioSessionAcquired(){ - haveAudioSession=true; - if(sharedInstance) - sharedInstance->ProcessAudioSessionAcquired(); -} - void AudioUnitIO::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ - if(configured) - return; -#ifdef TGVOIP_USE_AUDIO_SESSION - runFakeIO=true; - start_thread(fakeIOThread, AudioUnitIO::StartFakeIOThread, this); - set_thread_priority(fakeIOThread, get_thread_max_priority()); -#endif - - if(haveAudioSession){ - ActuallyConfigure(sampleRate, bitsPerSample, channels); - }else{ - cfgSampleRate=sampleRate; - cfgBitsPerSample=bitsPerSample; - cfgChannels=channels; - } - - configured=true; -} - -void AudioUnitIO::ActuallyConfigure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){ - UInt32 flag=1; - OSStatus status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag)); - CHECK_AU_ERROR(status, "Error enabling AudioUnit output"); - status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); - CHECK_AU_ERROR(status, "Error enabling AudioUnit input"); - - flag=ServerConfig::GetSharedInstance()->GetBoolean("use_ios_vpio_agc", true) ? 1 : 0; - status=AudioUnitSetProperty(unit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, kAudioUnitScope_Global, kInputBus, &flag, sizeof(flag)); - CHECK_AU_ERROR(status, "Error disabling AGC"); - - AudioStreamBasicDescription audioFormat; - audioFormat.mSampleRate = sampleRate; - audioFormat.mFormatID = kAudioFormatLinearPCM; - audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian; - audioFormat.mFramesPerPacket = 1; - audioFormat.mChannelsPerFrame = channels; - audioFormat.mBitsPerChannel = bitsPerSample*channels; - audioFormat.mBytesPerPacket = bitsPerSample/8*channels; - audioFormat.mBytesPerFrame = bitsPerSample/8*channels; - - status = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &audioFormat, sizeof(audioFormat)); - CHECK_AU_ERROR(status, "Error setting output format"); - status = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &audioFormat, sizeof(audioFormat)); - CHECK_AU_ERROR(status, "Error setting input format"); - - AURenderCallbackStruct callbackStruct; - - callbackStruct.inputProc = AudioUnitIO::BufferCallback; - callbackStruct.inputProcRefCon = this; - status = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &callbackStruct, sizeof(callbackStruct)); - CHECK_AU_ERROR(status, "Error setting output buffer callback"); - status = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callbackStruct, sizeof(callbackStruct)); - CHECK_AU_ERROR(status, "Error setting input buffer callback"); - - status = AudioUnitInitialize(unit); - CHECK_AU_ERROR(status, "Error initializing AudioUnit"); - status=AudioOutputUnitStart(unit); - CHECK_AU_ERROR(status, "Error starting AudioUnit"); } OSStatus AudioUnitIO::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ @@ -168,7 +152,6 @@ OSStatus AudioUnitIO::BufferCallback(void *inRefCon, AudioUnitRenderActionFlags } void AudioUnitIO::BufferCallback(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 bus, UInt32 numFrames, AudioBufferList *ioData){ - runFakeIO=false; if(bus==kOutputBus){ if(output && outputEnabled){ output->HandleBufferCallback(ioData); @@ -176,9 +159,9 @@ void AudioUnitIO::BufferCallback(AudioUnitRenderActionFlags *ioActionFlags, cons memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize); } }else if(bus==kInputBus){ + inBufferList.mBuffers[0].mDataByteSize=10240; + AudioUnitRender(unit, ioActionFlags, inTimeStamp, bus, numFrames, &inBufferList); if(input && inputEnabled){ - inBufferList.mBuffers[0].mDataByteSize=10240; - AudioUnitRender(unit, ioActionFlags, inTimeStamp, bus, numFrames, &inBufferList); input->HandleBufferCallback(&inBufferList); } } @@ -208,40 +191,127 @@ void AudioUnitIO::DetachOutput(){ void AudioUnitIO::EnableInput(bool enabled){ inputEnabled=enabled; + StartIfNeeded(); } void AudioUnitIO::EnableOutput(bool enabled){ outputEnabled=enabled; + StartIfNeeded(); } -void* AudioUnitIO::StartFakeIOThread(void *arg){ - ((AudioUnitIO*)arg)->RunFakeIOThread(); - return NULL; +void AudioUnitIO::StartIfNeeded(){ + if(started) + return; + started=true; + OSStatus status = AudioUnitInitialize(unit); + CHECK_AU_ERROR(status, "Error initializing AudioUnit"); + status=AudioOutputUnitStart(unit); + CHECK_AU_ERROR(status, "Error starting AudioUnit"); } -void AudioUnitIO::RunFakeIOThread(){ - double neededDataDuration=0; - double prevTime=VoIPController::GetCurrentTime(); - while(runFakeIO){ - double t=VoIPController::GetCurrentTime(); - neededDataDuration+=t-prevTime; - prevTime=t; - while(neededDataDuration>=0.020){ - if(output && outputEnabled){ - inBufferList.mBuffers[0].mDataByteSize=960*2; - output->HandleBufferCallback(&inBufferList); - } - if((output && outputEnabled) || (input && inputEnabled)){ - memset(inBufferList.mBuffers[0].mData, 0, 960*2); - } - if(input && inputEnabled){ - inBufferList.mBuffers[0].mDataByteSize=960*2; - input->HandleBufferCallback(&inBufferList); - } - neededDataDuration-=0.020; +bool AudioUnitIO::IsFailed(){ + return failed; +} + +#if TARGET_OS_OSX +OSStatus AudioUnitIO::DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData){ + AudioUnitIO* self=(AudioUnitIO*)inClientData; + if(inAddresses[0].mSelector==kAudioHardwarePropertyDefaultOutputDevice){ + LOGV("System default output device changed"); + if(self->currentOutputDevice=="default"){ + self->SetCurrentDevice(false, self->currentOutputDevice); + } + }else if(inAddresses[0].mSelector==kAudioHardwarePropertyDefaultInputDevice){ + LOGV("System default input device changed"); + if(self->currentInputDevice=="default"){ + self->SetCurrentDevice(true, self->currentInputDevice); } - usleep(5000); } - LOGD("FakeIO thread exiting"); + return noErr; } +void AudioUnitIO::SetCurrentDevice(bool input, std::string deviceID){ + if(started){ + AudioOutputUnitStop(unit); + AudioUnitUninitialize(unit); + } + UInt32 size=sizeof(AudioDeviceID); + AudioDeviceID device=NULL; + OSStatus status; + + if(deviceID=="default"){ + AudioObjectPropertyAddress propertyAddress; + propertyAddress.mSelector = input ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + UInt32 propsize = sizeof(AudioDeviceID); + status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propsize, &device); + CHECK_AU_ERROR(status, "Error getting default device"); + }else{ + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + UInt32 dataSize = 0; + status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize); + CHECK_AU_ERROR(status, "Error getting devices size"); + UInt32 deviceCount = (UInt32)(dataSize / sizeof(AudioDeviceID)); + AudioDeviceID audioDevices[deviceCount]; + status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, audioDevices); + CHECK_AU_ERROR(status, "Error getting device list"); + for(UInt32 i = 0; i < deviceCount; ++i) { + // Query device UID + CFStringRef deviceUID = NULL; + dataSize = sizeof(deviceUID); + propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; + status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceUID); + CHECK_AU_ERROR(status, "Error getting device uid"); + char buf[1024]; + CFStringGetCString(deviceUID, buf, 1024, kCFStringEncodingUTF8); + if(deviceID==buf){ + LOGV("Found device for id %s", buf); + device=audioDevices[i]; + break; + } + } + if(!device){ + LOGW("Requested device not found, using default"); + SetCurrentDevice(input, "default"); + return; + } + } + + status=AudioUnitSetProperty(unit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + input ? kInputBus : kOutputBus, + &device, + size); + CHECK_AU_ERROR(status, "Error setting input device"); + + if(input) + currentInputDevice=deviceID; + else + currentOutputDevice=deviceID; + + + /*AudioObjectPropertyAddress propertyAddress = { + kAudioDevicePropertyBufferFrameSize, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + size=4; + UInt32 bufferFrameSize; + status=AudioObjectGetPropertyData(device, &propertyAddress, 0, NULL, &size, &bufferFrameSize); + if(status==noErr){ + estimatedDelay=bufferFrameSize/48; + LOGD("CoreAudio buffer size for device is %u frames (%u ms)", bufferFrameSize, estimatedDelay); + }*/ + if(started){ + started=false; + StartIfNeeded(); + } +} + +#endif diff --git a/os/darwin/AudioUnitIO.h b/os/darwin/AudioUnitIO.h index b5e7aff764..42f08ff83e 100644 --- a/os/darwin/AudioUnitIO.h +++ b/os/darwin/AudioUnitIO.h @@ -8,7 +8,9 @@ #define LIBTGVOIP_AUDIOUNITIO_H #include +#include #include "../../threading.h" +#include namespace tgvoip{ namespace audio{ class AudioInputAudioUnit; @@ -25,33 +27,32 @@ public: void DetachOutput(); void EnableInput(bool enabled); void EnableOutput(bool enabled); + bool IsFailed(); static AudioUnitIO* Get(); static void Release(); - static void* StartFakeIOThread(void* arg); - static void AudioSessionAcquired(); +#if TARGET_OS_OSX + void SetCurrentDevice(bool input, std::string deviceID); +#endif private: static OSStatus BufferCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); void BufferCallback(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 bus, UInt32 numFrames, AudioBufferList* ioData); - void RunFakeIOThread(); - void Init(); - void ActuallyConfigure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels); - void ProcessAudioSessionAcquired(); + void StartIfNeeded(); +#if TARGET_OS_OSX + static OSStatus DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData); + std::string currentInputDevice; + std::string currentOutputDevice; +#endif AudioComponentInstance unit; AudioInputAudioUnit* input; AudioOutputAudioUnit* output; AudioBufferList inBufferList; - bool configured; bool inputEnabled; bool outputEnabled; - bool runFakeIO; - uint32_t cfgSampleRate; - uint32_t cfgBitsPerSample; - uint32_t cfgChannels; - tgvoip_thread_t fakeIOThread; + bool failed; + bool started; static int refCount; static AudioUnitIO* sharedInstance; - static bool haveAudioSession; }; }} diff --git a/os/windows/AudioInputWASAPI.cpp b/os/windows/AudioInputWASAPI.cpp index e5d621757c..0de718bfc9 100644 --- a/os/windows/AudioInputWASAPI.cpp +++ b/os/windows/AudioInputWASAPI.cpp @@ -61,12 +61,13 @@ AudioInputWASAPI::AudioInputWASAPI(std::string deviceID){ audioClient=NULL; captureClient=NULL; thread=NULL; + started=false; SetCurrentDevice(deviceID); } AudioInputWASAPI::~AudioInputWASAPI(){ - if(audioClient && isRecording){ + if(audioClient && started){ audioClient->Stop(); } @@ -109,15 +110,14 @@ void AudioInputWASAPI::Start(){ thread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AudioInputWASAPI::StartThread, this, 0, NULL); } - if(audioClient) + started=true; + if(audioClient){ audioClient->Start(); + } } void AudioInputWASAPI::Stop(){ isRecording=false; - - if(audioClient) - audioClient->Stop(); } bool AudioInputWASAPI::IsRecording(){ @@ -368,7 +368,8 @@ void AudioInputWASAPI::RunThread() { memcpy(remainingData+remainingDataLen, data, dataLen); remainingDataLen+=dataLen; while(remainingDataLen>960*2){ - InvokeCallback(remainingData, 960*2); + if(isRecording) + InvokeCallback(remainingData, 960*2); memmove(remainingData, remainingData+(960*2), remainingDataLen-960*2); remainingDataLen-=960*2; } diff --git a/os/windows/AudioInputWASAPI.h b/os/windows/AudioInputWASAPI.h index 3851f61fb2..d19d10ad26 100644 --- a/os/windows/AudioInputWASAPI.h +++ b/os/windows/AudioInputWASAPI.h @@ -77,6 +77,7 @@ private: bool isDefaultDevice; ULONG refCount; std::string streamChangeToDevice; + bool started; #ifdef TGVOIP_WINDOWS_DESKTOP STDMETHOD(OnDisplayNameChanged) (LPCWSTR /*NewDisplayName*/, LPCGUID /*EventContext*/) { return S_OK; };