diff --git a/EchoCanceller.cpp b/EchoCanceller.cpp index 0ca8a296ef..604a905693 100755 --- a/EchoCanceller.cpp +++ b/EchoCanceller.cpp @@ -185,6 +185,8 @@ void EchoCanceller::SetVoiceDetectionEnabled(bool enabled){ apm->voice_detection()->Enable(enabled); } +using namespace tgvoip::effects; + AudioEffect::~AudioEffect(){ } @@ -193,73 +195,41 @@ void AudioEffect::SetPassThrough(bool passThrough){ this->passThrough=passThrough; } -AutomaticGainControl::AutomaticGainControl(){ -#ifndef TGVOIP_NO_DSP - /*splittingFilter=new webrtc::SplittingFilter(1, 3, 960); - splittingFilterIn=new webrtc::IFChannelBuffer(960, 1, 1); - splittingFilterOut=new webrtc::IFChannelBuffer(960, 1, 3); +Volume::Volume(){ - agc=WebRtcAgc_Create(); - WebRtcAgcConfig agcConfig; - agcConfig.compressionGaindB = 9; - agcConfig.limiterEnable = 1; - agcConfig.targetLevelDbfs = 3; - WebRtcAgc_Init(agc, 0, 255, kAgcModeAdaptiveDigital, 48000); - WebRtcAgc_set_config(agc, agcConfig); - agcMicLevel=0;*/ -#endif } -AutomaticGainControl::~AutomaticGainControl(){ -#ifndef TGVOIP_NO_DSP - /*delete (webrtc::SplittingFilter*)splittingFilter; - delete (webrtc::IFChannelBuffer*)splittingFilterIn; - delete (webrtc::IFChannelBuffer*)splittingFilterOut; - WebRtcAgc_Free(agc);*/ -#endif +Volume::~Volume(){ + } -void AutomaticGainControl::Process(int16_t *inOut, size_t numSamples){ -#ifndef TGVOIP_NO_DSP - /*if(passThrough) - return; - if(numSamples!=960){ - LOGW("AutomaticGainControl only works on 960-sample buffers (got %u samples)", (unsigned int)numSamples); +void Volume::Process(int16_t* inOut, size_t numSamples){ + if(level==1.0f || passThrough){ return; } - //LOGV("processing frame through AGC"); - - webrtc::IFChannelBuffer* bufIn=(webrtc::IFChannelBuffer*) splittingFilterIn; - webrtc::IFChannelBuffer* bufOut=(webrtc::IFChannelBuffer*) splittingFilterOut; - - memcpy(bufIn->ibuf()->bands(0)[0], inOut, 960*2); - - ((webrtc::SplittingFilter*)splittingFilter)->Analysis(bufIn, bufOut); - - int i; - 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]; + for(size_t i=0;i32767.0f) + inOut[i]=INT16_MAX; + else if(sample<-32768.0f) + inOut[i]=INT16_MIN; + else + inOut[i]=(int16_t)sample; } - 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); - 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); - - memcpy(inOut, bufIn->ibuf_const()->bands(0)[0], 960*2);*/ -#endif } +void Volume::SetLevel(float level){ + this->level=level; + float db; + if(level<1.0f) + db=-50.0f*(1.0f-level); + else if(level>1.0f && level<=2.0f) + db=10.0f*(level-1.0f); + else + db=0.0f; + multiplier=expf(db/20.0f * logf(10.0f)); +} + +float Volume::GetLevel(){ + return level; +} diff --git a/EchoCanceller.h b/EchoCanceller.h index 3dff7cc27c..e684ba051b 100755 --- a/EchoCanceller.h +++ b/EchoCanceller.h @@ -51,28 +51,33 @@ private: #endif }; - class AudioEffect{ - public: - virtual ~AudioEffect()=0; - virtual void Process(int16_t* inOut, size_t numSamples)=0; - virtual void SetPassThrough(bool passThrough); - protected: - bool passThrough; - }; +namespace effects{ - class AutomaticGainControl : public AudioEffect{ - public: - AutomaticGainControl(); - virtual ~AutomaticGainControl(); - virtual void Process(int16_t* inOut, size_t numSamples); - - private: - void* agc; - void* splittingFilter; - void* splittingFilterIn; - void* splittingFilterOut; - int32_t agcMicLevel; - }; +class AudioEffect{ +public: + virtual ~AudioEffect()=0; + virtual void Process(int16_t* inOut, size_t numSamples)=0; + virtual void SetPassThrough(bool passThrough); +protected: + bool passThrough; }; +class Volume : public AudioEffect{ +public: + Volume(); + virtual ~Volume(); + virtual void Process(int16_t* inOut, size_t numSamples); + /** + * Level is (0.0, 2.0] + */ + void SetLevel(float level); + float GetLevel(); +private: + float level=1.0f; + float multiplier=1.0f; +}; + +} +} + #endif //LIBTGVOIP_ECHOCANCELLER_H diff --git a/MessageThread.cpp b/MessageThread.cpp index 775b530033..9af1441046 100755 --- a/MessageThread.cpp +++ b/MessageThread.cpp @@ -87,6 +87,10 @@ void MessageThread::Run(){ } #endif } + if(!running){ + queueMutex.Unlock(); + return; + } currentTime=VoIPController::GetCurrentTime(); std::vector msgsToDeliverNow; for(std::vector::iterator m=queue.begin();m!=queue.end();){ diff --git a/OpusDecoder.cpp b/OpusDecoder.cpp index 8081606840..0ecd63e508 100755 --- a/OpusDecoder.cpp +++ b/OpusDecoder.cpp @@ -187,8 +187,8 @@ void tgvoip::OpusDecoder::RunThread(){ unsigned char *buf=bufferPool->Get(); if(buf){ if(remainingDataLen>0){ - for(std::vector::iterator effect=postProcEffects.begin();effect!=postProcEffects.end();++effect){ - (*effect)->Process(reinterpret_cast(processedBuffer+(PACKET_SIZE*i)), 960); + for(effects::AudioEffect*& effect:postProcEffects){ + effect->Process(reinterpret_cast(processedBuffer+(PACKET_SIZE*i)), 960); } memcpy(buf, processedBuffer+(PACKET_SIZE*i), PACKET_SIZE); }else{ @@ -279,12 +279,12 @@ void tgvoip::OpusDecoder::SetLevelMeter(AudioLevelMeter *levelMeter){ this->levelMeter=levelMeter; } -void tgvoip::OpusDecoder::AddAudioEffect(AudioEffect *effect){ +void tgvoip::OpusDecoder::AddAudioEffect(effects::AudioEffect *effect){ postProcEffects.push_back(effect); } -void tgvoip::OpusDecoder::RemoveAudioEffect(AudioEffect *effect){ - std::vector::iterator i=std::find(postProcEffects.begin(), postProcEffects.end(), effect); +void tgvoip::OpusDecoder::RemoveAudioEffect(effects::AudioEffect *effect){ + std::vector::iterator i=std::find(postProcEffects.begin(), postProcEffects.end(), effect); if(i!=postProcEffects.end()) postProcEffects.erase(i); } diff --git a/OpusDecoder.h b/OpusDecoder.h index 81232d7027..572649185a 100755 --- a/OpusDecoder.h +++ b/OpusDecoder.h @@ -39,8 +39,8 @@ public: void SetJitterBuffer(std::shared_ptr jitterBuffer); void SetDTX(bool enable); void SetLevelMeter(AudioLevelMeter* levelMeter); - void AddAudioEffect(AudioEffect* effect); - void RemoveAudioEffect(AudioEffect* effect); + void AddAudioEffect(effects::AudioEffect* effect); + void RemoveAudioEffect(effects::AudioEffect* effect); private: void Initialize(bool isAsync, bool needEC); @@ -65,7 +65,7 @@ private: int consecutiveLostPackets; bool enableDTX; size_t silentPacketCount; - std::vector postProcEffects; + std::vector postProcEffects; bool async; unsigned char nextBuffer[8192]; unsigned char decodeBuffer[8192]; diff --git a/OpusEncoder.cpp b/OpusEncoder.cpp index 70dbb4002d..0eb50b61bd 100755 --- a/OpusEncoder.cpp +++ b/OpusEncoder.cpp @@ -149,6 +149,11 @@ void tgvoip::OpusEncoder::RunThread(){ bool hasVoice=true; if(echoCanceller) echoCanceller->ProcessInput(packet, 960, hasVoice); + if(!postProcEffects.empty()){ + for(effects::AudioEffect* effect:postProcEffects){ + effect->Process(packet, 960); + } + } if(packetsPerFrame==1){ Encode(packet, 960); }else{ @@ -238,3 +243,12 @@ void tgvoip::OpusEncoder::SetSecondaryEncoderEnabled(bool enabled){ void tgvoip::OpusEncoder::SetVadMode(bool vad){ vadMode=vad; } +void tgvoip::OpusEncoder::AddAudioEffect(effects::AudioEffect *effect){ + postProcEffects.push_back(effect); +} + +void tgvoip::OpusEncoder::RemoveAudioEffect(effects::AudioEffect *effect){ + std::vector::iterator i=std::find(postProcEffects.begin(), postProcEffects.end(), effect); + if(i!=postProcEffects.end()) + postProcEffects.erase(i); +} diff --git a/OpusEncoder.h b/OpusEncoder.h index 5a1fe83da1..bf919e06d4 100755 --- a/OpusEncoder.h +++ b/OpusEncoder.h @@ -38,6 +38,8 @@ public: void SetCallback(void (*f)(unsigned char*, size_t, unsigned char*, size_t, void*), void* param); void SetSecondaryEncoderEnabled(bool enabled); void SetVadMode(bool vad); + void AddAudioEffect(effects::AudioEffect* effect); + void RemoveAudioEffect(effects::AudioEffect* effect); private: static size_t Callback(unsigned char* data, size_t len, void* param); @@ -66,6 +68,7 @@ private: bool secondaryEncoderEnabled; bool vadMode=false; uint32_t vadNoVoiceBitrate; + std::vector postProcEffects; void (*callback)(unsigned char*, size_t, unsigned char*, size_t, void*); void* callbackParam; diff --git a/VoIPController.cpp b/VoIPController.cpp index 620ebb35f5..a0574d5c32 100755 --- a/VoIPController.cpp +++ b/VoIPController.cpp @@ -191,8 +191,6 @@ VoIPController::VoIPController() : activeNetItfName(""), udpConnectivityState=UDP_UNKNOWN; echoCancellationStrength=1; - outputAGC=NULL; - outputAGCEnabled=false; peerCapabilities=0; callbacks={0}; didReceiveGroupCallKey=false; @@ -299,8 +297,6 @@ VoIPController::~VoIPController(){ if(resolvedProxyAddress) delete resolvedProxyAddress; delete selectCanceller; - if(outputAGC) - delete outputAGC; LOGD("Left VoIPController::~VoIPController"); } @@ -741,9 +737,6 @@ void VoIPController::SetCallbacks(VoIPController::Callbacks callbacks){ void VoIPController::SetAudioOutputGainControlEnabled(bool enabled){ LOGD("New output AGC state: %d", enabled); - outputAGCEnabled=enabled; - if(outputAGC) - outputAGC->SetPassThrough(!enabled); } uint32_t VoIPController::GetPeerCapabilities(){ @@ -885,6 +878,24 @@ vector VoIPController::GetPersistentState(){ return vector(jstr, jstr+strlen(jstr)); } +void VoIPController::SetOutputVolume(float level){ + outputVolume.SetLevel(level); +} + +void VoIPController::SetInputVolume(float level){ + inputVolume.SetLevel(level); +} + +#if defined(__APPLE__) && defined(TARGET_OS_OSX) +void VoIPController::SetAudioOutputDuckingEnabled(bool enabled){ + macAudioDuckingEnabled=enabled; + audio::AudioUnitIO* osxAudio=dynamic_cast(audioIO); + if(osxAudio){ + osxAudio->SetDuckingEnabled(enabled); + } +} +#endif + #pragma mark - Internal intialization void VoIPController::InitializeTimers(){ @@ -1093,7 +1104,7 @@ void VoIPController::InitializeAudio(){ double t=GetCurrentTime(); shared_ptr& outgoingAudioStream=outgoingStreams[0]; LOGI("before create audio io"); - audioIO=audio::AudioIO::Create(); + audioIO=audio::AudioIO::Create(currentAudioInput, currentAudioOutput); audioInput=audioIO->GetInput(); audioOutput=audioIO->GetOutput(); #ifdef __ANDROID__ @@ -1109,6 +1120,8 @@ void VoIPController::InitializeAudio(){ LOGI("Forcing software NS because built-in is not good"); } } +#elif defined(__APPLE__) && defined(TARGET_OS_OSX) + SetAudioOutputDuckingEnabled(macAudioDuckingEnabled); #endif LOGI("AEC: %d NS: %d AGC: %d", config.enableAEC, config.enableNS, config.enableAGC); echoCanceller=new EchoCanceller(config.enableAEC, config.enableNS, config.enableAGC); @@ -1117,6 +1130,9 @@ void VoIPController::InitializeAudio(){ encoder->SetOutputFrameDuration(outgoingAudioStream->frameDuration); encoder->SetEchoCanceller(echoCanceller); encoder->SetSecondaryEncoderEnabled(false); + if(config.enableVolumeControl){ + encoder->AddAudioEffect(&inputVolume); + } #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) dynamic_cast(audioInput)->SetDataCallback(audioInputDataCallback); @@ -1153,11 +1169,11 @@ void VoIPController::StartAudio(){ void VoIPController::OnAudioOutputReady(){ LOGI("Audio I/O ready"); shared_ptr& stm=incomingStreams[0]; - outputAGC=new AutomaticGainControl(); - outputAGC->SetPassThrough(!outputAGCEnabled); stm->decoder=make_shared(audioOutput, true, peerVersion>=6); - stm->decoder->AddAudioEffect(outputAGC); stm->decoder->SetEchoCanceller(echoCanceller); + if(config.enableVolumeControl){ + stm->decoder->AddAudioEffect(&outputVolume); + } stm->decoder->SetJitterBuffer(stm->jitterBuffer); stm->decoder->SetFrameDuration(stm->frameDuration); stm->decoder->Start(); @@ -3617,3 +3633,46 @@ Endpoint::~Endpoint(){ delete socket; } } + +#pragma mark - AudioInputTester + +AudioInputTester::AudioInputTester(std::string deviceID) : deviceID(deviceID){ + io=audio::AudioIO::Create(deviceID, "default"); + if(io->Failed()){ + LOGE("Audio IO failed"); + return; + } + input=io->GetInput(); + input->SetCallback([](unsigned char* data, size_t size, void* ctx) -> size_t{ + reinterpret_cast(ctx)->Update(reinterpret_cast(data), size/2); + return 0; + }, this); + input->Start(); + /*thread=new MessageThread(); + thread->Start(); + thread->Post([this]{ + this->callback(maxSample/(float)INT16_MAX); + maxSample=0; + }, updateInterval, updateInterval);*/ +} + +AudioInputTester::~AudioInputTester(){ + //thread->Stop(); + //delete thread; + input->Stop(); + delete io; +} + +void AudioInputTester::Update(int16_t *samples, size_t count){ + for(size_t i=0;imaxSample) + maxSample=s; + } +} + +float AudioInputTester::GetAndResetLevel(){ + float s=maxSample; + maxSample=0; + return s/(float)INT16_MAX; +} diff --git a/VoIPController.h b/VoIPController.h index 8eb30b3233..99a375cadd 100755 --- a/VoIPController.h +++ b/VoIPController.h @@ -158,7 +158,24 @@ namespace tgvoip{ }; class AudioInputDevice : public AudioDevice{ - + + }; + + class AudioInputTester{ + public: + AudioInputTester(const std::string deviceID); + ~AudioInputTester(); + TGVOIP_DISALLOW_COPY_AND_ASSIGN(AudioInputTester); + float GetAndResetLevel(); + bool Failed(){ + return io && io->Failed(); + } + private: + void Update(int16_t* samples, size_t count); + audio::AudioIO* io=NULL; + audio::AudioInput* input=NULL; + int16_t maxSample=0; + std::string deviceID; }; class VoIPController{ @@ -194,6 +211,7 @@ namespace tgvoip{ bool enableCallUpgrade; bool logPacketStats=false; + bool enableVolumeControl=false; }; struct TrafficStats{ @@ -399,6 +417,12 @@ namespace tgvoip{ }; void SetVideoSource(video::VideoSource* source); void SetVideoRenderer(video::VideoRenderer* renderer); + + void SetInputVolume(float level); + void SetOutputVolume(float level); +#if defined(__APPLE__) && defined(TARGET_OS_OSX) + void SetAudioOutputDuckingEnabled(bool enabled); +#endif private: struct Stream; @@ -659,8 +683,6 @@ namespace tgvoip{ std::string proxyPassword; IPv4Address* resolvedProxyAddress; - AutomaticGainControl* outputAGC; - bool outputAGCEnabled; uint32_t peerCapabilities; Callbacks callbacks; bool didReceiveGroupCallKey; @@ -696,11 +718,17 @@ namespace tgvoip{ uint32_t initTimeoutID=MessageThread::INVALID_ID; uint32_t noStreamsNopID=MessageThread::INVALID_ID; uint32_t udpPingTimeoutID=MessageThread::INVALID_ID; + + effects::Volume outputVolume; + effects::Volume inputVolume; #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) std::function audioInputDataCallback; std::function audioOutputDataCallback; #endif +#if defined(__APPLE__) && defined(TARGET_OS_OSX) + bool macAudioDuckingEnabled=true; +#endif video::VideoSource* videoSource=NULL; video::VideoRenderer* videoRenderer=NULL; diff --git a/audio/AudioIO.cpp b/audio/AudioIO.cpp index b99be79218..2c16ca701f 100644 --- a/audio/AudioIO.cpp +++ b/audio/AudioIO.cpp @@ -47,8 +47,7 @@ using namespace tgvoip; using namespace tgvoip::audio; using namespace std; -AudioIO* AudioIO::Create(){ - std::string inputDevice="default", outputDevice="default"; +AudioIO* AudioIO::Create(std::string inputDevice, std::string outputDevice){ #if defined(TGVOIP_USE_CALLBACK_AUDIO_IO) return new AudioIOCallback(); #elif defined(__ANDROID__) @@ -59,7 +58,7 @@ AudioIO* AudioIO::Create(){ return new ContextlessAudioIO(inputDevice, outputDevice); #endif - return new AudioUnitIO(); + return new AudioUnitIO(inputDevice, outputDevice); #elif defined(_WIN32) #ifdef TGVOIP_WINXP_COMPAT if(LOBYTE(LOWORD(GetVersion()))<6) diff --git a/audio/AudioIO.h b/audio/AudioIO.h index 0bc10e9f15..e60af25b51 100644 --- a/audio/AudioIO.h +++ b/audio/AudioIO.h @@ -21,7 +21,7 @@ namespace tgvoip{ AudioIO(){}; virtual ~AudioIO(){}; TGVOIP_DISALLOW_COPY_AND_ASSIGN(AudioIO); - static AudioIO* Create(); + static AudioIO* Create(std::string inputDevice, std::string outputDevice); virtual AudioInput* GetInput()=0; virtual AudioOutput* GetOutput()=0; bool Failed(); diff --git a/json11.cpp b/json11.cpp index 9647846b6d..a969859fab 100755 --- a/json11.cpp +++ b/json11.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include namespace json11 { @@ -618,7 +620,11 @@ struct JsonParser final { i++; } - return std::strtod(str.c_str() + start_pos, nullptr); + std::istringstream stm(std::string(str.begin()+start_pos, str.end())); + stm.imbue(std::locale("C")); + double result; + stm >> result; + return result; } /* expect(str, res) diff --git a/os/darwin/AudioInputAudioUnitOSX.cpp b/os/darwin/AudioInputAudioUnitOSX.cpp index d85a113622..e9218b1891 100644 --- a/os/darwin/AudioInputAudioUnitOSX.cpp +++ b/os/darwin/AudioInputAudioUnitOSX.cpp @@ -201,6 +201,8 @@ void AudioInputAudioUnitLegacy::EnumerateDevices(std::vector& dev.displayName=std::string(buf); CFStringGetCString(deviceUID, buf, 1024, kCFStringEncodingUTF8); dev.id=std::string(buf); + if(dev.id.rfind("VPAUAggregateAudioDevice-0x")==0) + continue; devs.push_back(dev); } diff --git a/os/darwin/AudioOutputAudioUnitOSX.cpp b/os/darwin/AudioOutputAudioUnitOSX.cpp index 13f132a031..cc023f8ebd 100644 --- a/os/darwin/AudioOutputAudioUnitOSX.cpp +++ b/os/darwin/AudioOutputAudioUnitOSX.cpp @@ -222,6 +222,8 @@ void AudioOutputAudioUnitLegacy::EnumerateDevices(std::vector dev.displayName=std::string(buf); CFStringGetCString(deviceUID, buf, 1024, kCFStringEncodingUTF8); dev.id=std::string(buf); + if(dev.id.rfind("VPAUAggregateAudioDevice-0x")==0) + continue; devs.push_back(dev); } diff --git a/os/darwin/AudioUnitIO.cpp b/os/darwin/AudioUnitIO.cpp index eefc914228..8806c322e5 100644 --- a/os/darwin/AudioUnitIO.cpp +++ b/os/darwin/AudioUnitIO.cpp @@ -23,10 +23,19 @@ #define kOutputBus 0 #define kInputBus 1 +#if TARGET_OS_OSX +extern "C" { +OSStatus AudioDeviceDuck(AudioDeviceID inDevice, + Float32 inDuckedLevel, + const AudioTimeStamp* __nullable inStartTime, + Float32 inRampDuration) __attribute__((weak_import)); +} +#endif + using namespace tgvoip; using namespace tgvoip::audio; -AudioUnitIO::AudioUnitIO(){ +AudioUnitIO::AudioUnitIO(std::string inputDeviceID, std::string outputDeviceID){ input=NULL; output=NULL; inputEnabled=false; @@ -108,11 +117,13 @@ AudioUnitIO::AudioUnitIO(){ AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioUnitIO::DefaultDeviceChangedCallback, this); propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, AudioUnitIO::DefaultDeviceChangedCallback, this); + + #endif - input=new AudioInputAudioUnit("default", this); - output=new AudioOutputAudioUnit("default", this); + input=new AudioInputAudioUnit(inputDeviceID, this); + output=new AudioOutputAudioUnit(outputDeviceID, this); } AudioUnitIO::~AudioUnitIO(){ @@ -162,6 +173,10 @@ void AudioUnitIO::EnableInput(bool enabled){ void AudioUnitIO::EnableOutput(bool enabled){ outputEnabled=enabled; StartIfNeeded(); + if(actualDuckingEnabled!=duckingEnabled){ + actualDuckingEnabled=duckingEnabled; + AudioDeviceDuck(currentOutputDeviceID, duckingEnabled ? 0.177828f : 1.0f, NULL, 0.1f); + } } void AudioUnitIO::StartIfNeeded(){ @@ -200,6 +215,7 @@ OSStatus AudioUnitIO::DefaultDeviceChangedCallback(AudioObjectID inObjectID, UIn } void AudioUnitIO::SetCurrentDevice(bool input, std::string deviceID){ + LOGV("Setting current %sput device: %s", input ? "in" : "out", deviceID.c_str()); if(started){ AudioOutputUnitStop(unit); AudioUnitUninitialize(unit); @@ -264,7 +280,6 @@ void AudioUnitIO::SetCurrentDevice(bool input, std::string deviceID){ else currentOutputDevice=deviceID; - /*AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyBufferFrameSize, kAudioObjectPropertyScopeGlobal, @@ -281,6 +296,18 @@ void AudioUnitIO::SetCurrentDevice(bool input, std::string deviceID){ started=false; StartIfNeeded(); } + if(!input){ + currentOutputDeviceID=device; + } + LOGV("Set current %sput device done", input ? "in" : "out"); +} + +void AudioUnitIO::SetDuckingEnabled(bool enabled){ + duckingEnabled=enabled; + if(outputEnabled && duckingEnabled!=actualDuckingEnabled){ + actualDuckingEnabled=enabled; + AudioDeviceDuck(currentOutputDeviceID, enabled ? 0.177828f : 1.0f, NULL, 0.1f); + } } #endif diff --git a/os/darwin/AudioUnitIO.h b/os/darwin/AudioUnitIO.h index 24d550adea..dac8f84dd9 100644 --- a/os/darwin/AudioUnitIO.h +++ b/os/darwin/AudioUnitIO.h @@ -19,7 +19,7 @@ class AudioOutputAudioUnit; class AudioUnitIO : public AudioIO{ public: - AudioUnitIO(); + AudioUnitIO(std::string inputDeviceID, std::string outputDeviceID); ~AudioUnitIO(); void EnableInput(bool enabled); void EnableOutput(bool enabled); @@ -27,6 +27,7 @@ class AudioOutputAudioUnit; virtual AudioOutput* GetOutput(); #if TARGET_OS_OSX void SetCurrentDevice(bool input, std::string deviceID); + void SetDuckingEnabled(bool enabled); #endif private: @@ -37,10 +38,13 @@ class AudioOutputAudioUnit; static OSStatus DefaultDeviceChangedCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData); std::string currentInputDevice; std::string currentOutputDevice; + bool duckingEnabled=true; + bool actualDuckingEnabled=true; #endif AudioComponentInstance unit; AudioInputAudioUnit* input; AudioOutputAudioUnit* output; + AudioDeviceID currentOutputDeviceID; AudioBufferList inBufferList; bool inputEnabled; bool outputEnabled;