音频文件在播放时出现断断续续或类似“爆破”(Pop-Click)杂音的现象,称之为 Xrun(可以是 underrun,也可以是 overrun)。
【原因】
通常来说,出现 Xrun 问题时原因可能是以下几个之一:
(1) Linux CFS 调度器导致。因为 CFS 调度器的“公平调度”是较长一段时间的平均表现,在很短的一个窗口时间段内,CFS 也可能会将 CPU 时间片完全分配给一个 nice 值更高的线程而不顾及另一个 nice 值更低的线程。如果这个低 nice 值的线程恰好是音频相关的,就会导致 Xrun 问题。
(2) 更高优先级的 SCHED_FIFO 线程调度。除了音频线程以外,其它线程也可以使用 SCHED_FIFO 标记,如果这个其它线程的优先级高于音频线程,那么它会被优先调度。这样也会导致 Xrun 问题。
(3) 优先级反转。所谓的优先级反转是指一个更高优先级的线程需要使用另一个更低优先级线程所持有的资源,而不得不等待低优先级线程在使用完毕后将资源释放掉。如果音频线程恰好是这个高优先级线程,此时也将导致 Xrun 问题。
(4) 过长的调度延时。
(5) 顶半部中断处理程序执行时间过长。
(6) 禁用中断时间过长。
(7) 电源管理。内核会对芯片的工作电源进行适时地控制以免芯片温度过高而烧毁,这些管理策略可能会暂时挂起芯片中正在进行的工作。如果音频相关的任务因此被挂起,那么就会出现 Xrun 问题。
(8) 内核安全策略原因。
【解决办法】
最好的解决办法当然是分析出 Xrun 的问题到底是上面哪个原因导致的,然后对症下药的改动相应的代码以修复问题。但并不是所有人都对内核各部分了如指掌能精确定位到问题代码的位置(我承认至少我还没有那个水平),所以这里有一个类似万金油的办法:增加音频数据的 buffer 大小或 buffer 数量来进行补偿。但这样也会使音频播放/录音的 数据准备时间变长,也就是说会增加音频操作的延迟,算是这种方法的一个副作用。
插入耳机开机随机出现POP音
分析思路:通过音量渐进设置来播放开机铃声,达到消除POP音
执行步骤:先静音-->开始播放开机铃声-->延迟200ms-->设置开机铃声的音量
结论:此方法也不能很好的消除POP音问题。最后做了一个极端实验:把开机铃声静音后,插入耳机测试发现也会出现随机性的POP音。
由此得出:应该是耳机音频通路上电、打开的时候产生了POP音。由于耳机PA位于耳机音频通路的末端,最后上电、打开。所以确定耳机PA上电时序异常导致此POP音产生。
解决方案:
耳机PA上电代码定位:AudioMachineDevice.cpp文件的AnalogOpen()函数。
case AudioAnalogType::DEVICE_OUT_HEADSETR:
case AudioAnalogType::DEVICE_OUT_HEADSETL:
…….
mAudioAnalogReg->SetAnalogReg(0x0706, 0x0082, 0xffff); // short HS tovcm and HS output stability EnhanceParasNum
mAudioAnalogReg->SetAnalogReg(0x0702, 0x0009, 0xffff); // open andheadset power on
usleep(1000);
mAudioAnalogReg->SetAnalogReg(0x0704, 0x0940, 0xffff); // not shortHP to vcm
mAudioAnalogReg->SetAnalogReg(0x0702, 0x000F, 0xffff); //HP power on
usleep(1000);
mAudioAnalogReg->SetAnalogReg(0x0704, 0x0100, 0xffff); // HP enhance
……
耳机PA上电代码见红色部分。
解决方法:
从示波器看,此POP音的持续时间是25ms左右,所以代码将延迟30ms再上电、打开耳机PA。
代码修改如下所示:
……
usleep(30*1000); // add by baibo cancel headsetpop noise when phone with headset boot
mAudioAnalogReg->SetAnalogReg(0x0702,0x000F, 0xffff); // HP power on
……
结论:通过延迟打开耳机PA消除此POP音。经过压力测试,此问题没有再复现。
POP声是指音频器件在上电、断电瞬间以及上电稳定后,各种操作带来的瞬态冲击所产生的爆破声。
下文结合自身在推广小功率D类音频功放IC的过程中遇到的设计问题,就音频系统开关机POP声的解决思路和大家分享一下。
降低或去除POP声方案:
检查并确认D类功放IC音频输入端电容的值(左右声道各两个)均为104或更小(4个电容值必须相同);
原理说明:
POP声产生的原因与输入电容有关,主要是输入电容充放电造成了POP声,所以输入电容适当减小可以减小POP声。
方法一:D类功放IC关断脚SDL和SDR对GND接电容(见下图)。
原理说明:
SDL和SDR为低电平有效,当其处于低电平时电路处于关断状态,所以一上电就使电路处于关断状态就不会产生POP声。原来的电路一上电关断脚是高电平,关断功能失效,所以在该脚对GND接一个22uF左右大电容后,关断脚由于需要对电容充电,所以D类音频功放IC上电以后,关断脚不能马上达到高电平,当电容充电到一定状态后,关断脚达到高电平,D类音频功放IC才能正常工作。所以利用电容充电的时间差,可以避开POP声的产生。电容值可以根据实际情况进行调节。
方法二:修改D类音频IC的MUTE端部分外围(具体修改方法见下图中红色圆圈内部分内容)。
原理说明:
原来电路中MUTE脚一上电处于低电平状态,此时MUTE功能失效,D类音频功放IC可以正常工作,对电路进行修改在MUTE控制端串入电阻6R14,对VCC接4.7uF左右电容后,电路上电后MUTE端电容进行充电,所以该脚上电后先是高电平,接着6R14进行放电,MUTE端电压值慢慢降低到低电平。所以使用MUTE与VCC的上电时序也可以避开POP声部分。电容6C23的值可以根据实际情况进行调节,该电容值越大,MUTE与VCC错开的时序越久。
杂音 & pop 音的解决方法
1. 喇叭有严重的“吱吱”破音,绝大多数的原因有可能在于V(out)电压不稳定,所以最好测一下无负载时的输出电压。同时也可以测量 VCC –即boost 的输出/输入电压。正常的VCC 可以通过客户的 反馈电阻和 VCC负载电阻求得。
2、客户有杂音:估计是信号的干扰,一般是电源的干扰因素占最大的比重,建议测量静态电流 IQ 。
3、POP 音:这个POP音说到底是因为codec开始工作时,耳机声道上的直流电平跳变产生的;手机或一般的手持设备上不会有负电压,音源信号必须在一个直流电平上(如1/2VDD上)输出,这样一个从0电平到1/2VDD的直流跳变,通过隔直电容电容后到耳机上必然会产生POP音。说到底还是搁置电容充放电的声音。
4、POP 音的减小方法:
方法一:一般来说, IC 上、掉电时的 POP 音是由于偏置电压的瞬间跳变引起的。所以要减小 POP 音就必须抑制 IC 的偏执电压Vbias 的瞬变。Layout 上的体现方法就是增大 Vbias 的滤波电容。对于 TPA6132 来说参考设计是 1 uF 但是偏置电容变得过大会导致 IC 的建立时间变长,会让人感觉声音“久久”没有出来。另外电容过大还会导致 THD+N 变差。
方法二:对于 TPA6132,我们通过改变时序,是在噪声出来之前关掉class , 通过软件修 改 Depop_mute#和Speaker_mute# 的时序,使其提前关闭。
方法三:电源开启噪声,地平面反弹的噪声(如一些解码芯片的beep pin接地后,由地噪声引起的不受speak off控制的pop声),等等,首要的是要查明来源。再找方法。如找不到或找到后无法解决,那可以试一下串一个电阻,对pop声的幅值进行压制,当然这也减少了耳机的最大音量。
方法四:还有一种方法:就是预充电的方法,再加上上拉和下拉电阻将电容的直流电压稳定住,可能效果会比较好。当然首先要确认这个直流偏置1/2VDD到底是多高(有些是可以设置的,有些固定),才好设计上下拉电阻的大小,这样调整后,感觉效果还可以,pop noise几乎感觉不到。
方法五:现在有些CODEC在软件上有一个寄存器可以设置这个直流电平的上升时间,让它在一定时间内跳变到1/2VDD,而不是很陡的一个上升沿,这样可以在一定程度改善这个POP音。
5、开关机的POP 音问题目前是整个音频功放的瓶颈问题,目前最好的一个解决方法是方法二。对于我们的 Demo 来说,例如切换歌曲的时候,可以先按住 EN 给他一个 low 信号,然后等音乐切换结束的时候再放开
6、补充:左右声道都是采用全差分方式输出的话,那是不需要隔直电容,但是耳机就不能够用标准四线耳机插孔,这种全差分的方式,耳机一般都是用的专用输出插头(与调试接口共用)。
7、特别注意 DEMO 的时候要共地,减小 POP 音产生的可能,检测的时候也会有标准。
dump audio数据定位音频问题
android产品开发过程中,经常会遇到一些音频问题,比如杂音、破音。这个时候需要快速定位问题点。
这里介绍一个遇到的案例,简单描述下问题的定位过程。
环境:
ubuntu 16.04 + android (amlogic ARM)
问题:
android产品作为被动蓝牙(类似蓝牙音箱),电脑蓝牙链接后播放1KHZ的正弦波音频,出现破音。android本地播放该音频,无破音。
分析:
首先需要确定硬件还是软件的问题,因为涉及硬件的问题可能会block改版和生产,所以非常急迫。这里硬件涉及codec、功放、喇叭。因为破音非常大的可能性是音频截止了。所以分析音频是最直接有效的方法。
首先音频源文件是标准的1KHZ正弦波,扫频也不没发现错误点,一个锅先扔了。然后音频通过蓝牙传给了android,那我们抓一下第一手的数据,就是在audio的HAL层dump出数据。美妙的是,amlogic、高通等的代码都有现成的,放开调试就可以生成想要的文件信息。
/hardware/amlogic/audio/audio_hw.c
static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
size_t bytes)
{
int ret = 0;
size_t oldBytes = bytes;
struct aml_stream_out *out = (struct aml_stream_out *)stream;
struct aml_audio_device *adev = out->dev;
size_t frame_size = audio_stream_out_frame_size(stream);
size_t in_frames = bytes / frame_size;
size_t out_frames;
bool force_input_standby = false;
int16_t *in_buffer = (int16_t *)buffer;
struct aml_stream_in *in;
char output_buffer_bytes[RESAMPLER_BUFFER_SIZE + 128];
uint ouput_len;
char *data, *data_dst;
volatile char *data_src;
uint i, total_len;
int codec_type = 0;
int samesource_flag = 0;
uint32_t latency_frames = 0;
int need_mix = 0;
short *mix_buf = NULL;
unsigned char enable_dump = getprop_bool("media.audiohal.outdump");
…………
…………
…………
#if 1
if (enable_dump && out->hw_sync_mode == 0) {
FILE *fp1 = fopen("/data/tmp/i2s_audio_out.pcm", "a+");
if (fp1) {
int flen = fwrite((char *)buffer, 1, bytes, fp1);
fclose(fp1);
}
}
#endif
…………
…………
}
很明显,out_write函数中,只要打开enable_dump就会把音频dump到/data/tmp/i2s_audio_out.pcm中。
enable_dump是由“media.audiohal.outdump”控制,getprop你会发现这个应该是空的。只需要setprop media.audiohal.outdump 1 就可开始抓音频。
抓下音频,adb pull导入到电脑中,用万能的audacity进行分析:
这里可以看到,音频并没有破音,而且丢帧了。通过频谱分析看异常频点会更加清晰。
可以发现,这样的丢帧还是比较多的。
所以这里可以排除硬件的问题了,问题定位到蓝牙丢帧上。
蓝牙的丢帧,可以继续跟踪它的overrun和underrun,后续文章会有详细过程。
关于android的audiotrack播放声音断断续续的问题
int bufsize = AudioTrack.getMinBufferSize(22050, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
audioplayer = new AudioTrack(AudioManager.STREAM_MUSIC, 22050, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufsize, AudioTrack.MODE_STREAM);
主要是因为buffer设置的太小了,将其改为:
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufsize*4, AudioTrack.MODE_STREAM); 即可
解决音频功放造成的pop音问题。
1. 创建延迟队列要绑定的延迟处理函数
-
void msm8952_pa_reset_func(struct work_struct *work)
-
{
-
struct msm8916_asoc_mach_data *pdata = NULL;
-
struct delayed_work *dwork;
-
dwork = to_delayed_work(work);
-
pdata = container_of(dwork, struct msm8916_asoc_mach_data, pa_reset_work);
-
gpio_set_value(pdata->spk_ext_pa_sdb_gpio, GPIO_HIGH);
-
gpio_set_value(pdata->spk_ext_pa_sdd_gpio, GPIO_HIGH);
-
}
2. 初始化队列并绑定延迟处理函数
INIT_DELAYED_WORK(&pdata->pa_reset_work, msm8952_pa_reset_func);
3. 在条件触发的地方调用该延迟队列
-
static int enable_spk_ext_pa(struct snd_soc_codec *codec, int enable)
-
{
-
struct snd_soc_card *card = codec->component.card;
-
struct msm8916_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
-
if(enable){
-
schedule_delayed_work(&pdata->pa_reset_work, msecs_to_jiffies(20));
-
pr_err("@@@@@@@@ ENABLE TPA @@@@@@@@@@@\n");
-
} else {
-
gpio_set_value(pdata->spk_ext_pa_sdd_gpio, GPIO_LOW);
-
gpio_set_value(pdata->spk_ext_pa_sdb_gpio, GPIO_LOW);
-
mdelay(100);
-
pr_err("@@@@@@@@ DISABLE TPA @@@@@@@@@@\n");
-
}
-
return 0;
-
}
【Qualcomm高通音频】音效调试_播放音乐时,声音忽大忽小,声音有明显处理的痕迹
将/vendor/etc 或 /system/etc下面当前项目使用的mixer_paths_xxx.xml文件pull出来,检查speaker path 配置,如图:
如果有红色框图中的配置,将其删除后再进行测试验证。
这两项配置与codec中的设置相关,该设置用于信号开启和关闭压缩扩展功能,会引起信号异常。
如何判定通话场景中的喇叭发出的滋滋声从哪产生的
测试步骤如下:
1、建立通话
2、对方不说话
3、对方机器进行静音操作
4、 切换不同sim卡,重复测试,
分析如下:
1. 如果对方静音后,滋滋声消失,则该问题为音频软件问题
2. 如果对方静音后,滋滋声仍然存在,原因有2种可能:
a. 如果只是gsm通话存在该滋滋声问题,则为Tdd_oise问题,安排硬件同事帮忙解决。
b. 如果所有网络制式通话均存在该滋滋声问题,则为PA底噪问题,应该安排硬件同事帮忙解决。
开或者关音乐时有pop音怎么办
POP音产生的原因基本上是PA打开与音源输送的时序不当导致,可按如下时序配置软件驱动代码。
一、 上电时序:
① 打开codec输出。
② PA SHDN 拉高送入脉冲。
③ 40ms后送入相应音源。(因为功放需要启动时间,启动40ms后才有输出)
二、掉电时序:
① 关闭音源。
② PA SHDN拉低(注意在功放SHDN脚被拉低后1ms后再关闭codec输出,并且SHDN拉低后这个时间内信号不要有变化,有变化会被放大出来)。
③ 1ms以后关闭codec输出。
案例1:
客户应用某高通平台项目触摸时有POP音。一开始在打开GPIO处DELAY了100ms,没有作用。
加成1s,发现POP音在1s后出现,也就是说POP音也延后了1s。
后面客户工程师在GPIO打开之前加了个队列函数
(init_delayed_work(&msm8x16_wcd_priv>work,set_gpio_enable_work)
另外在GPIO之前那段代码:
void set_gpio_enable(struct msm8x16_wcd_priv *msm8x16_wcd)
然后再做GPIO拉高拉低动作拉高动作,这样解决了上电POP音。
案例2:
1.首先确认输入的电容是否一样,图上的C739和C740,如果C739和C740差异过大可能会产生POP音,
如果是客户输入为L何R 声道通过电容连在一起接在INN或INP上,那么INN和INP的等效电电容值要一样。
2.如果有receiver和spk共用的情况,要查看是否有模拟开关,如果直接把SPK接在PUM的receiver输出上,
由于PA输出电平和PUM输出电平不一样,导致PA开启和关闭的POP音较大,听起来比较明显,所以必须用模拟开关切换,否则存在漏电的可能,POP音也会比较明显。
3.音源和PA的打开关闭时序控制,导致的POP音,客户提的比较多的是关闭PA产生的POP音,正常时序为PA的EN脚拉低大于300us,建议在1ms以上,然后再关闭PUM模拟输出。
由于艾为PA关断有300us左右的延时,在PA关闭前最好音源不要有较大的变化,下面是MKT平台的处理时序,
从下面抓到时序图时可以看到,POP音就是产生于PA的EN脚拉低后150us的时候有一段突变和较大的噪音出来,然后突然就没有了,POP音就是这时候产生的。
解决办法是在的脚拉低后延时大于300us在关闭的模拟输出,如下图,
POP音有明显的减小,为了保证延时和芯片关断时间的差异性,建议PA的EN脚拉低1ms后关闭PUM的模拟输出。软件具体修改办法,
MTK平台有关于POP音的修改的FAQ,需要登录MTK官方网站的FAQ查看
Pop音的几种原因及解决方案
1、硬件贴片错误可能会导致pop音,比如两个输入电容的容值相差过大,一个33nf,一个1uf,这时在播放音乐的开始阶段可能会发生POP音;
2、时序控制不合理也会导致POP音,正确的时序应该为:开启时,先开启BB音源,delay 20~30ms,然后再开启功放,关闭时,采用先关闭功放,delay20~30ms,然后再关闭音源。
3、音源本身可能会产生类似POP音的异常音,可以尝试修改或更换音源解决。 另外,软件上如果能采用淡进淡出的处理,也就是打开的时候,逐渐增大音量,关断的时候,逐渐减小音量,效果会更好。
//
引起POP原因可能有多种,可排查以下几点:
(1)音源与PA开启关断时序不合理(可通过抓取音频PA的输入,输出波形与PA使能引脚波形来判定)
上电时序:1.打开codec输出。2.PA SHDN 拉高送入脉冲。3.40ms后送入相应音源。
下电时序:1.关闭相应音源。2.PA SHDN拉低。3.1ms以后关闭codec输出。
(2)输入电容,电阻失配引起;
(3)原理图错误:AB类差分输入应用;
(4)音源本身问题;
(5)控制音频PA使能引脚的GPIO口下拉能力弱,或其他地方有上拉,导致长时间未关断;
(6)软件对音源做淡进淡出处理