AudioRecord:缓冲区溢出?

8
我在我的应用程序中使用 Service 进行录制时,遇到了缓冲区溢出的问题。我无法确定为什么会从AudioFlinger接收到此错误消息。

下面是我实例化 AudioRecord 对象并设置其回调函数的代码:

bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
aRecorder = new AudioRecord(audioSource, sampleRate, channelConfig, audioFormat, bufferSize);

aRecorder.setRecordPositionUpdateListener(updateListener);

bytesPerSample = bitsPerSample / 8;
int bytesPerFrame = nChannels * bytesPerSample;
framePeriod = bufferSize / bytesPerFrame; // nr of frames that can be kept in a bufferSize dimension    
int result = aRecorder.setPositionNotificationPeriod(framePeriod);    
buffer = new byte[bufferSize];

音频记录回调函数:
private AudioRecord.OnRecordPositionUpdateListener updateListener = new AudioRecord.OnRecordPositionUpdateListener(){
        public void onPeriodicNotification(AudioRecord recorder){
            int result = aRecorder.read(buffer, 0, buffer.length);
        }

        public void onMarkerReached(AudioRecord recorder)
        {}
    };

我猜测问题与以下代码有关: aRecorder.setPositionNotificationPeriod(framePeriod);,可能是周期对于这个bufferSize来说太大了,通过更快(更小)的周期可以解决问题。
请问有人知道如何消除缓冲区溢出吗?
2个回答

10

要修复该问题,请将AudioRecord的缓冲区大小更改为最小缓冲区大小的2倍。

您可以使用AudioRecord.getMinBufferSize()静态方法。这会为您提供当前格式所需使用的最小缓冲区大小。

getMinBufferSize()方法的语法如下:

public static int getMinBufferSize (
    int sampleRateInHz, int channelConfig, int audioFormat)

如果这个数字比要求的更小,创建 AudioRecord 对象时将会失败。

你应该减小缓冲区的大小,以免对音频子系统产生数据需求过大的压力。

记得按照以下方式写 audioRecord 回调的重写方法 (@Override):

private AudioRecord.OnRecordPositionUpdateListener updateListener = new AudioRecord.OnRecordPositionUpdateListener(){

        @Override
        public void onPeriodicNotification(AudioRecord recorder){
            int result = aRecorder.read(buffer, 0, buffer.length);
        }

        @Override
        public void onMarkerReached(AudioRecord recorder)
        {}
    };
我建议阅读这篇文章:Android音频录制,part 2 还有一件事,您可以尝试的是在录制和其他处理记录字节上使用线程,从而避免主UI线程过载。
此方法的开源示例代码:musicg_android_demo 查看此帖子以获取更多信息 - android-audiorecord-class-process-live-mic-audio-quickly-set-up-callback-func

感谢您的回答,所有数据处理都在辅助线程中完成。bufferSize是使用AudioRecord的静态方法(getMinBufSize)获取的。确实缺少了@overwrite。 - Alexandru Circus
昨天我尝试将minBufSize乘以2,但只是减少了“BufferOverlow”消息的频率到约30秒。无论如何,乘以2到目前为止是我尝试过的最好的变体,但我想完全摆脱它,因为我的录音在1小时3分钟后停止。 - Alexandru Circus
那就是说,在乘以2之后,就没有缓冲区溢出的问题了,但录音在一定时间后停止了?您可以尝试在释放录音器之前重置它。 - My God
不,将其乘以2之后,溢出仍然存在,但从每10秒减少到约30秒,并且录制现在在1小时后停止(之前在20分钟后停止)。我认为发布/记录是以适当的方式完成的。 - Alexandru Circus
我通过使用一个线程来轮询从AudioRecord获取数据并丢弃回调的方式解决了这个问题,就像在musicg_android_demo中一样。我成功地录制了2小时而没有停止。我将进行更多测试,并在一切正常时给您+50赏金。 - Alexandru Circus
@AlexandruCircus,你能分享一下你的解决方案吗? - anhtuannd

2
那是因为:
framePeriod = bufferSize / bytesPerFrame;

你需要将缓冲区的大小乘以而不是除以。

尝试使用以下代码:

framePeriod = bufferSize * bytesPerFrame;

如果您需要示例:这里有一个完整的音频捕获类

希望对您有所帮助


缓冲区应该按照以下方式实例化:buffer = new byte[framePeriod * bytesPerFrame]。谢谢。 - Alexandru Circus
我会尝试跟随您提供的链接。我看到它使用了一个次要线程来记录,而不是回调变体(onPeriodicNotification)。 - Alexandru Circus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接