苹果ios音频的回声消除处理
iOS设备上回声消除的例子
工业上的声音处理中,回声消除是一个重要的话题,重要性不亚于噪声消除、人声放大、自动增益等,尤其是在VoIP功能上,回声消除是每一个做VoIP功能团队的必修课。QQ、Skype等等,回声消除的效果是一个重要的考查指标。
具体的回声消除算法比较复杂,我现在还没有研究的很明白。简单来说,就是在即将播放出来的声音中,将回声的那部分减去。其中一个关键,是如何估计回声大小,这需要用到自适应算法。研究不透,多说无益。有兴趣的同学可以一起学习。
Apple在Core Audio中提供了回声消除的接口,我写了一个测试APP,测试了其效果。链接:https://github.com/lixing123/iOSEchoCancellation
下面讲一下如何实现。
将声音输出route到speaker,这样声音比较大,回声明显:
AVAudioSession* session = [AVAudioSession sharedInstance];
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
[session setActive:YES error:nil];
初始化一个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 subtype
inputcd.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
inputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
配置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 output
streamFormat.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 callback
AURenderCallbackStruct input;
input.inputProc = InputCallback;
input.inputProcRefCon = myStruct;
CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
0,//input mic
&input,
sizeof(input)),
"kAudioUnitProperty_SetRenderCallback failed");
在回调函数inputCallback中,用
AudioUnitRender()
函数获取麦克风的声音,存在一个bufferList中。这个bufferList是一个ring结构,存储最新的声音,然后播放旧声音。这样,声音的输入和输出之间,就有了0.5s(可调节)左右的延迟,形成了明显的回声。给回声消除添加一个开关。VoiceProcessingIO有一个属性可用来打开/关闭回声消除功能:
kAUVoiceIOProperty_BypassVoiceProcessing
UInt32 echoCancellation;
UInt32 size = sizeof(echoCancellation);
CheckError(AudioUnitGetProperty(myStruct.remoteIOUnit,
kAUVoiceIOProperty_BypassVoiceProcessing,
kAudioUnitScope_Global,
0,
&echoCancellation,
&size),
"kAUVoiceIOProperty_BypassVoiceProcessing failed");
现在可以开始graph了:
CheckError(AUGraphInitialize(graph),
"AUGraphInitialize failed");
CheckError(AUGraphStart(graph),
"AUGraphStart failed");
在示例中,有一个简单的开关按钮,可以明显感觉到打开/关闭回声消除的区别。
在实测中,打开回声消除功能时,仍然能听到一点点的回声,不过很小,一般情况下足够使用了。
工业上的声音处理中,回声消除是一个重要的话题,重要性不亚于噪声消除、人声放大、自动增益等,尤其是在VoIP功能上,回声消除是每一个做VoIP功能团队的必修课。QQ、Skype等等,回声消除的效果是一个重要的考查指标。
具体的回声消除算法比较复杂,我现在还没有研究的很明白。简单来说,就是在即将播放出来的声音中,将回声的那部分减去。其中一个关键,是如何估计回声大小,这需要用到自适应算法。研究不透,多说无益。有兴趣的同学可以一起学习。
Apple在Core Audio中提供了回声消除的接口,我写了一个测试APP,测试了其效果。链接:https://github.com/lixing123/iOSEchoCancellation
下面讲一下如何实现。
将声音输出route到speaker,这样声音比较大,回声明显:
AVAudioSession* session = [AVAudioSession sharedInstance]; [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil]; [session setActive:YES error:nil];
- 1
- 2
- 3
初始化一个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 subtype inputcd.componentSubType = kAudioUnitSubType_VoiceProcessingIO; inputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
- 1
- 2
- 3
- 4
- 5
- 6
配置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 output streamFormat.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 callback AURenderCallbackStruct input; input.inputProc = InputCallback; input.inputProcRefCon = myStruct; CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,kAudioUnitProperty_SetRenderCallback,kAudioUnitScope_Global,0,//input mic&input,sizeof(input)),"kAudioUnitProperty_SetRenderCallback failed");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
在回调函数inputCallback中,用
AudioUnitRender()
函数获取麦克风的声音,存在一个bufferList中。这个bufferList是一个ring结构,存储最新的声音,然后播放旧声音。这样,声音的输入和输出之间,就有了0.5s(可调节)左右的延迟,形成了明显的回声。给回声消除添加一个开关。VoiceProcessingIO有一个属性可用来打开/关闭回声消除功能:
kAUVoiceIOProperty_BypassVoiceProcessing
UInt32 echoCancellation; UInt32 size = sizeof(echoCancellation); CheckError(AudioUnitGetProperty(myStruct.remoteIOUnit,kAUVoiceIOProperty_BypassVoiceProcessing,kAudioUnitScope_Global,0,&echoCancellation,&size),"kAUVoiceIOProperty_BypassVoiceProcessing failed");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
现在可以开始graph了:
CheckError(AUGraphInitialize(graph),"AUGraphInitialize failed"); CheckError(AUGraphStart(graph),"AUGraphStart failed");
- 1
- 2
- 3
- 4
在示例中,有一个简单的开关按钮,可以明显感觉到打开/关闭回声消除的区别。
在实测中,打开回声消除功能时,仍然能听到一点点的回声,不过很小,一般情况下足够使用了。
iOS 音频-AVAudioSession
iOS音频掌柜-- AVAudioSession
在WebRTC应用中,AudioUnit 使用的是Voice-Processing I / O unit (subtype kAudioUnitSubType_VoiceProcessingIO),使用内置的aec和agc等功能, AVAudioSession状态:
Category = AVAudioSessionCategoryPlayAndRecord,Mode = AVAudioSessionModeVoiceChat,无须显式的setMode,使用 Voice-Processing I / O unit 会自动切换为 VoiceChat,至于Options依实际业务情景需求设置。
- Category 切换成 AVAudioSessionCategoryPlayback:
那么AudioUnit record cb 有回调,但是获取到的是静音数据。 - 使用AVAudioPlayer播放音频文件,音量非常低:
可以通过调整mode解决, 播放音频文件时设置为 AVAudioSessionModeDefault,待播放完毕之后再设置为 AVAudioSessionModeVoiceChat。但是这个缺点是,切换成 default mode 后 失去了回音消除功能了。
然而,像狼人杀的场景,需要一直播放背景音乐,又需要对话过程中回音消除,那么就需要好好的维护好 mode 和 option了。
0人点赞
日记本
作者:暴走大牙
链接:https://www.jianshu.com/p/5addd678c64e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
苹果ios音频的回声消除处理相关推荐
- 音频应用(如sip与Voip),编解码API(Ringtone,SoundPool,MediaPlayer),回声消除等(Lame Speex等),OpenSL ES
3套音频播放API:MediaPlayer,SoundPool,AudioTrack. android录音项目,用单例模式集成了record,并实时转码mp3- https://github.com/ ...
- 音频前处理:回声消除、噪声抑制等(音视频SDK高级功能六)
音频前处理技术一般用于去除语音中的干扰.本篇文章介绍即构科技音视频SDK高级功能第六篇,ZegoLiveRoom SDK 为开发者提供了音频前处理的功能,还是以iOS环境为例. 关于如何使用SDK,请 ...
- 可视监控对讲、楼宇对讲等领域中的回声消除、音频降噪
在实际生活中,对讲是比较常用的功能,如小区单元的视频对讲.监控场所的实时对讲,还有现在很火的智能门铃中的视频对讲,对讲这个功能确实方便了双方的沟通,但这功能的实现并不是那么容易,因为有个技术是较难实现 ...
- 微处理器(STM32 wifi芯片)实现音频回声消除
一.什么是回声消除(AEC) 在回答回声消除之前,我们看这幅图片,如下图所示: 当远端Far-end有说话者讲话时,声音会传到近端(Near-end)的扬声器,然后声音通过空间延时和传输延时重新回到了 ...
- 音视频处理三剑客之 AEC:回声产生原因及回声消除原理
在上一期课程<音视频开发者进阶 -- 音频要素>中,我们从声音三要素.音频模拟信号的数字化和音频数字信号特征等方面,重新认识了"声音"这个老朋友.今天,我们会进一步聊聊 ...
- 【iOS】iOS语音通话回音消除(AEC)技术实现
一.前言 在语音聊天.语音通话.互动直播.语音转文字类应用或者游戏中,需要采集用户的麦克风音频数据,然后将音频数据发送给其它终端或者语音识别服务.如果直接使用采集的麦克风数据,就会存在回音问题.所谓回 ...
- 硬货专栏 |深入浅出 WebRTC AEC(声学回声消除)
前言:近年来,音视频会议产品提升着工作协同的效率,在线教育产品突破着传统教育形式的种种限制,娱乐互动直播产品丰富着生活社交的多样性,背后都离不开音视频通信技术的优化与创新,其中音频信息内容传递的流畅性 ...
- iOS音频采集过程中的音效实现
1.背景 在移动直播中, 声音是主播和观众互动的重要途径之一, 为了丰富直播的内容,大家都会想要在声音上做一些文章, 在采集录音的基础上玩一些花样. 比如演唱类的直播间中, 主播伴随着背景音乐演唱. ...
- 苹果iOS 15发布:关机也能定位,ASMR重度用户狂喜,这波库克又“去苹果化”了...
梦晨 萧箫 发自 凹非寺 量子位 报道 | 公众号 QbitAI 万众瞩目的苹果iOS 15正式版终于来了! 最受关注的更新,要属"实况文本",现在复制图中的文字就像复制文本一样简 ...
最新文章
- 中国治理蝗灾是生物防治的成就,根本不是靠鸡靠鸭靠吃货换来的!
- signavio-core-components ant build-all-in-one-war failed
- R语言实现多线性回归模型预测时间序列数据 MLR models in R
- ubuntu服务器在虚拟机中的配置
- Panda和numpy库和matplotlib库的安装
- sv队列和动态数组的区别_systemverilog学习(4)动态数组
- IT餐馆—第二十五回 结对
- 虚拟机CentOS8 网络配置
- 谷歌中国开发者大会,感悟,激动
- 管理口SSH服务存在拒绝服务漏洞(CVE-2016-6515)
- 关于jquery mobile 页面闪烁与抖动问题
- 如何把DEBIAN变成UBUNTU-DESKTOP最少化安装
- 数字图像隐写术之卡方分布
- 数仓建模—数据资产管理
- html让字数超过多少,css强制省略号 css设置超过多少个字显示省略号
- (八)高德地图之添加marker标记点
- SpringMVC常用方法大全
- linux中python怎么退出_linux 怎么退出python
- mysql数据库 去除回车符,换行符,和空格
- miix4linux双系统,联想MIIX4笔记本U盘重装win10系统教程