iOS裝置上回聲消除的例子

來源:互聯網
上載者:User

標籤:ios   聲音   回聲消除   

工業上的聲音處理中,回聲消除是一個重要的話題,重要性不亞於雜訊消除、人聲放大、自動增益等,尤其是在VoIP功能上,回聲消除是每一個做VoIP功能團隊的必修課。QQ、Skype等等,回聲消除的效果是一個重要的考查指標。

具體的回聲消除演算法比較複雜,我現在還沒有研究的很明白。簡單來說,就是在即將播放出來的聲音中,將回聲的那部分減去。其中一個關鍵,是如何估計回聲大小,這需要用到自適應演算法。研究不透,多說無益。有興趣的同學可以一起學習。

Apple在Core Audio中提供了回聲消除的介面,我寫了一個測試APP,測試了其效果。連結:https://github.com/lixing123/iOSEchoCancellation
下面講一下如何?。

  1. 將聲音輸出route到speaker,這樣聲音比較大,回聲明顯:

    AVAudioSession* session = [AVAudioSession sharedInstance];[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];[session setActive:YES error:nil];
  2. 初始化一個AUGraph,建立一個AUNode,並將之添加到graph上。一般來說,溝通麥克風/擴音器的AUNode,其類型應該是RemoteIO,但是RemoteIO不帶回聲消除功能,VoiceProcessingIO類型的才帶。

    AudioComponentDescription inputcd = {0};inputcd.componentType = kAudioUnitType_Output;//inputcd.componentSubType = kAudioUnitSubType_RemoteIO;//we can access the system‘s echo cancellation by using kAudioUnitSubType_VoiceProcessingIO subtypeinputcd.componentSubType = kAudioUnitSubType_VoiceProcessingIO;inputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
  3. 配置AudioUnit的屬性,開啟與麥克風/擴音器的串連(這個比較難以理解,可以參考Apple文檔:https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/UsingSpecificAudioUnits/UsingSpecificAudioUnits.html),並配置client data format(僅支援Linear PCM格式);配置回呼函數。

    //Open input of the bus 1(input mic)UInt32 enableFlag = 1;CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,                            kAudioOutputUnitProperty_EnableIO,                            kAudioUnitScope_Input,                            1,                            &enableFlag,                            sizeof(enableFlag)),       "Open input of bus 1 failed");//Open output of bus 0(output speaker)CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,                            kAudioOutputUnitProperty_EnableIO,                            kAudioUnitScope_Output,                            0,                            &enableFlag,                            sizeof(enableFlag)),       "Open output of bus 0 failed");//Set up stream format for input and outputstreamFormat.mFormatID = kAudioFormatLinearPCM;streamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;streamFormat.mSampleRate = 44100;streamFormat.mFramesPerPacket = 1;streamFormat.mBytesPerFrame = 2;streamFormat.mBytesPerPacket = 2;streamFormat.mBitsPerChannel = 16;streamFormat.mChannelsPerFrame = 1;CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,                            kAudioUnitProperty_StreamFormat,                            kAudioUnitScope_Input,                            0,                            &streamFormat,                            sizeof(streamFormat)),       "kAudioUnitProperty_StreamFormat of bus 0 failed");CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,                            kAudioUnitProperty_StreamFormat,                            kAudioUnitScope_Output,                            1,                            &streamFormat,                            sizeof(streamFormat)),       "kAudioUnitProperty_StreamFormat of bus 1 failed");//Set up input callbackAURenderCallbackStruct input;input.inputProc = InputCallback;input.inputProcRefCon = myStruct;CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,                            kAudioUnitProperty_SetRenderCallback,                            kAudioUnitScope_Global,                            0,//input mic                            &input,                            sizeof(input)),       "kAudioUnitProperty_SetRenderCallback failed");
  4. 在回呼函數inputCallback中,用AudioUnitRender() 函數擷取麥克風的聲音,存在一個bufferList中。這個bufferList是一個ring結構,儲存最新的聲音,然後播放舊聲音。這樣,聲音的輸入和輸出之間,就有了0.5s(可調節)左右的延遲,形成了明顯的回聲。

  5. 給回聲消除添加一個開關。VoiceProcessingIO有一個屬性可用來開啟/關閉回聲消除功能:kAUVoiceIOProperty_BypassVoiceProcessing

    UInt32 echoCancellation;UInt32 size = sizeof(echoCancellation);CheckError(AudioUnitGetProperty(myStruct.remoteIOUnit,                            kAUVoiceIOProperty_BypassVoiceProcessing,                            kAudioUnitScope_Global,                            0,                            &echoCancellation,                            &size),       "kAUVoiceIOProperty_BypassVoiceProcessing failed");
  6. 現在可以開始graph了:

    CheckError(AUGraphInitialize(graph),       "AUGraphInitialize failed");CheckError(AUGraphStart(graph),       "AUGraphStart failed");

    在樣本中,有一個簡單的開關按鈕,可以明顯感覺到開啟/關閉回聲消除的區別。

    在實測中,開啟回聲消除功能時,仍然能聽到一點點的回聲,不過很小,一般情況下足夠使用了。

iOS裝置上回聲消除的例子

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.