Android8.1 audioflinger overrun问题解决

platform:px30(rk平台)

OS:Android8.1

问题描述:在使用系统录音机以及其他录音软件录音时,会出现apk 录制回来的音频会出现部分数据丢失的情况,导致录制的音频会出现节奏跳动等异常现象!

后经过排查,发现是因为audioflinger 获取音频数据时出现了overrun 的情况导致数据丢失!

贴上overrun 报错部分代码(frameworks/av/services/audioflinger/Threads.cpp):

        // Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
        // Only the client(s) that are too slow will overrun. But if even the fastest client is too
        // slow, then this RecordThread will overrun by not calling HAL read often enough.
        // If destination is non-contiguous, first read past the nominal end of buffer, then
        // copy to the right place.  Permitted because mRsmpInBuffer was over-allocated.

        int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
        ssize_t framesRead;
        
        // If an NBAIO source is present, use it to read the normal capture's data
        if (mPipeSource != 0) {
            size_t framesToRead = mBufferSize / mFrameSize;
            framesToRead = min(mRsmpInFramesOA - rear, mRsmpInFramesP2 / 2);
            framesRead = mPipeSource->read((uint8_t*)mRsmpInBuffer + rear * mFrameSize,
							framesToRead);
            ALOGW("framesRead :%zd framesToRead :%zd \n",framesRead,framesToRead);
            // since pipe is non-blocking, simulate blocking input by waiting for 1/2 of
            // buffer size or at least for 20ms.
            size_t sleepFrames = max(
                    min(mPipeFramesP2, mRsmpInFramesP2) / 2, FMS_20 * mSampleRate / 1000);
            if (framesRead <= (ssize_t) sleepFrames) {
                sleepUs = (sleepFrames * 1000000LL) / mSampleRate;
            }
            if (framesRead < 0) {
                status_t status = (status_t) framesRead;
                switch (status) {
                case OVERRUN:
                    ALOGW("overrun on read from pipe");
                    framesRead = 0;
                    break;
                case NEGOTIATE:
                    ALOGE("re-negotiation is needed");
                    framesRead = -1;  // Will cause an attempt to recover.
                    break;
                default:
                    ALOGE("unknown error %d on read from pipe", status);
                    break;
                }
            }
        // otherwise use the HAL / AudioStreamIn directly
        }

通过代码可以看见当framesToRead参数,也就是获取一帧数据的缓冲区大小不够接收由底层获取到的数据时,read 函数就会返回OVERRUN,出现overrun 时,缓冲区就被置0,这一帧的数据也就相对的丢失了。

分析了原因后,现提出解决办法,首先需要确认audio hal 设置的帧数据缓冲区,代码位置hardware/rockchip/audio/tinyalsa_hal/audio_hw.h

struct pcm_config pcm_config_in = {
    .channels = 4,
    .rate = 48000,//44100,
#ifdef SPEEX_DENOISE_ENABLE
    .period_size = 1024,
#else
    .period_size = 480,//256,
#endif
    .period_count = 8,
    .format = PCM_FORMAT_S16_LE,
    .flag = HW_PARAMS_FLAG_LPCM,
};

period_size 和period_count 这两个参数就是缓冲区大小,这儿我设置的480 和8.

确定了这儿设置的参数,改起来就很简单了,在上面的Threads.cpp中修改:

framesRead = mPipeSource->read((uint8_t*)mRsmpInBuffer + rear * mFrameSize,
                    3840);//framesToRead);

3840是period_size * period_count的大小,在读取音频数据时,hal 传输的数据大小,与audioflinger 获取到的数据大小一致,则能保证缓冲区不会因为数据读取过短,或者hal 层数据传输过快,导致缓冲区溢出。

这顺便分享遇见音频问题的一般调试办法:

录音问题:一般先确定驱动录制的音频没有问题,可以使用Androidsdk 里提供的tinycap 工具录制从硬件mic 直接传输回的数据,tinycap 源码位于/external/tinyalsa/ 下,可以设置多种采样率,采样位数,通道数,录制wav 文件,使用audacity软件分析音频,如音频异常,需要检查音频驱动,平台端和codec 端,问题大多出在clk 不同步。

底层获取到的音频数据没问题时,就往上排查,到audio hal ,hal 是调用/external/tinyalsa/pcm.c 里面的接口获取数据,在hal 层可抓取debug 音频,在audio_hw.c 中添加

#define ALSA_IN_DEBUG
#ifdef ALSA_IN_DEBUG
FILE *in_debug;
#endif

#ifdef ALSA_IN_DEBUG
    in_debug = fopen("/data/debug.pcm","wb");//please touch /data/debug.pcm first
#endif

#ifdef ALSA_IN_DEBUG
                fwrite(buffer,frames_wr * frame_size,1,in_debug);
#endif

这儿给的示例,具体fwrite参数需要根据你自定义的参数写入,不然写入的数据会是一堆乱码,这儿不知道怎么给参数的,欢迎私信!

我这儿排查到audioflinger 的overrun 问题,也是在驱动层和hal层抓取的debug音频文件没问题,才查到audioflinger ,

最后就是排查audioflinger ,这一层涉及到的代码量较大,建议说根据具体的log 报错位置去排查!

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值