由于pcm_read()在Galaxy S4上返回错误n -5,gainBuffer超时

时间:2014-02-03 21:56:57

标签: android samsung-mobile audiorecord

我有一个使用AudioRecord API在Android设备上捕获音频的应用程序,它在Galaxy S4设备上反复失败。在尝试使用AudioRecord和MediaRecorder(例如AudioRec HQ)录制音频的其他应用程序中也会出现这种情况。我能够使用下面的代码在测试应用程序中重现它:

final int bufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_RECOGNITION, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize << 2);
mAudioRecord.startRecording();

mRecordThread = new Thread(new Runnable() {
    @Override
    public void run() {
        BufferedOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new BufferedOutputStream(new FileOutputStream(String.format(Locale.US, "/sdcard/%1$d.pcm", System.currentTimeMillis())));
            final byte[] buffer = new byte[bufferSize];
            int bytesRead;
            do {
                bytesRead = mAudioRecord.read(buffer, 0, buffer.length);
                if (bytesRead > 0) {
                    fileOutputStream.write(buffer, 0, bytesRead);
                }
            }
            while (bytesRead > 0);
        } catch (Exception e) {
            Log.e("RecordingTestApp", e.toString());
        }
    }
});
mRecordThread.start();

这些是相关的logcat条目:

02-03 15:36:10.913: W/AudioRecord(20986): obtainBuffer timed out (is the CPU pegged?) user=001699a0, server=001699a0
02-03 15:36:11.394: E/alsa_pcm(208): Arec: error5
02-03 15:36:11.394: W/AudioStreamInALSA(208): pcm_read() returned error n -5, Recovering from error
02-03 15:36:11.424: D/ALSADevice(208): close: handle 0xb7730148 h 0x0
02-03 15:36:11.424: D/ALSADevice(208): open: handle 0xb7730148, format 0x2
02-03 15:36:11.424: D/ALSADevice(208): Device value returned is hw:0,0
02-03 15:36:11.424: V/ALSADevice(208): flags 11000000, devName hw:0,0
02-03 15:36:11.424: V/ALSADevice(208): pcm_open returned fd 39
02-03 15:36:11.424: D/ALSADevice(208): handle->format: 0x2
02-03 15:36:11.434: D/ALSADevice(208): setHardwareParams: reqBuffSize 320 channels 1 sampleRate 8000
02-03 15:36:11.434: W/AudioRecord(20986): obtainBuffer timed out (is the CPU pegged?) user=001699a0, server=001699a0
02-03 15:36:11.444: D/ALSADevice(208): setHardwareParams: buffer_size 640, period_size 320, period_cnt 2
02-03 15:36:20.933: W/AudioRecord(20986): obtainBuffer timed out (is the CPU pegged?) user=0017ade0, server=0017ade0
02-03 15:36:21.394: E/alsa_pcm(208): Arec: error5
02-03 15:36:21.394: W/AudioStreamInALSA(208): pcm_read() returned error n -5, Recovering from error
02-03 15:36:21.424: D/ALSADevice(208): close: handle 0xb7730148 h 0x0
02-03 15:36:21.424: D/ALSADevice(208): open: handle 0xb7730148, format 0x2
02-03 15:36:21.424: D/ALSADevice(208): Device value returned is hw:0,0
02-03 15:36:21.424: V/ALSADevice(208): flags 11000000, devName hw:0,0
02-03 15:36:21.424: V/ALSADevice(208): pcm_open returned fd 39
02-03 15:36:21.424: D/ALSADevice(208): handle->format: 0x2
02-03 15:36:21.434: D/ALSADevice(208): setHardwareParams: reqBuffSize 320 channels 1 sampleRate 8000
02-03 15:36:21.434: D/ALSADevice(208): setHardwareParams: buffer_size 640, period_size 320, period_cnt 2
02-03 15:36:21.454: W/AudioRecord(20986): obtainBuffer timed out (is the CPU pegged?) user=0017ade0, server=0017ade0

这是完整的logcat: http://pastebin.com/y3XQ1rMf

发生这种情况时不会抛出任何异常,AudioRecord.read只会阻塞,直到硬件恢复并再次开始录制,但会丢失2-4秒的音频数据,因此对于用户而言,他们的音频文件缺少大面积区域非常烦人没有任何解释为什么。

这是一个已知的硬件问题,还是我应该采用不同的方式来更可靠地记录? 有没有办法检测到这个问题已经发生

2 个答案:

答案 0 :(得分:0)

我手边没有星系,但我看到你的例子有些不对劲。

new AudioRecord(MediaRecorder.AudioSource.VOICE_RECOGNITION, 8000,

首先以8000 Hz的采样率初始化AudioRecord。根据文档,只保证44100可用。 8000 Hz采样率可能根本就不存在。因此,您应该检查AudioRecord是否处于正确的状态。那就是:

mAudioRecord.getState()==STATE_INITIALIZED

您也可能想要检查getMinimumBufferSize的返回值。如果是ERROR_BAD_VALUE,那么您传递的参数不正确。

然后,一旦完成,您可能希望在将读取数据的线程中开始记录。这很可能不是您的问题的原因,但通常不清楚当发生溢出时audiodrivers会发生什么。例如:如果你没有足够快地读取数据,那么硬件可能产生了太多数据。 alsa drviers通常会根据谁制作它们而表现不同。因此,为了避免这个问题,最好在开始录制之前直接编写startRecording,因此在这种情况下,在runnable中。

完成后,您可能需要查看

mAudioRecord.getRecordingState()==RECORDING_RECORDING

如果没有录音,那么驱动程序已经告诉你有问题。

完成录制后,您还应该停止播放设备。同样,如果你自己没有关闭它们,一些alsa驱动程序会关闭超时,这意味着下次你尝试打开它们时,你可能根本就没有访问权限(这当然是非常特定的Linux)。

所以,乍一看这些是我要采取的途径,我的猜测是组合样本/通道配置不可用。

最后,我也感觉参数VOICE_RECOGNITION可能已关闭。也许只需用DEFAULT替换它。我过去曾经遇到过一些问题。

答案 1 :(得分:0)

使用AudioRecord尝试各种各样的频率,缓冲区大小和音频源以及使用MediaRecorder的多种格式后,如果没有这些pcm错误,我就无法录制音频。我从Play商店下载的几个录音应用程序发生了同样的错误。

我按照这个tutorial来创建一个OpenSL ES jni库并且它运行良好,我会向任何在Galaxy S4上看到这些错误的人推荐这种方法