我使用 AudioRecord 在 wav 文件中录制音频。我在辅助线程上的循环中执行 read() 操作,数据在另一秒内传递到队列中。用于写入文件的线程。
问题如下: 当我选择将音频数据保存在外部 SD 卡中时,音频包含一些跳音/失真(仅有时)。其他用户在内部 SD 卡上保存时也遇到此问题
这是我实例化 AudioRecord 对象的方式:
initBufferSize = assureMinBufferSize();
if (minBufferSize == AudioRecord.ERROR_BAD_VALUE) {
throw new Exception("" + ErrorCodes.ERROR_CODE_0);
}
else if (minBufferSize == AudioRecord.ERROR) {
throw new Exception("" + ErrorCodes.ERROR_CODE_0);
}
buffer = new byte[initBufferSize];
aRecorder = new AudioRecord(mSource, sRate, nChannel, AudioFormat.ENCODING_PCM_16BIT, initBufferSize);
这就是我池化 AudioRecorder 对象的方式:
private class AudioReaderRunnable implements Runnable {
private volatile boolean stopped;
@Override
public void run() {
while (!stopped) {
while(mState == State.RECORDING){
read();
}
}
Log.i(getClass().getName(), "AudioReade thread stopped!");
}
private void read(){
if(aRecorder == null)
return;
// "dirty" patch for some null crash for some users
if(buffer == null)
buffer = new byte[initBufferSize];
//int x = aRecorder.read(buffer, 0, buffer.length);
int x = readFully(buffer, 0, buffer.length);
if(x <= 0)
return;
payloadSize += x;
mWavData.arrayCopy(buffer);
mWavData.setGain(rGain);
mWavData.setBitsPerSamples(bitsPerSample);
mWavData.setNrChannels(nChannelsNumber);
// send audio to another thread for writing
mAudioWritter.add(audioData);
}
private int readFully(byte[] data, int off, int length) {
int read = 0;
int result = 0;
int requestedSize = length;
if(aRecorder == null){
return read;
}
try {
result = aRecorder.read(data, off, requestedSize);
} catch (Exception e) {
Log.e(getClass().getName(), e.getMessage(), e);
if(aRecorder == null)
return read;
}
read = result;
while (requestedSize != result && !stopped) {
if(aRecorder == null)
return read;
requestedSize -= result;
try {
result = aRecorder.read(data, result - 1, requestedSize);
} catch (Exception e) {
Log.e(getClass().getName(), e.getMessage(), e);
if(aRecorder == null)
return read;
}
read += result;
}
return read;
}
public void stopThread() {
stopped = true;
}
}
最佳答案
我在 Xamarin.Android 上遇到了类似的问题,这就是我解决它的方法:
AudioRecord 缓冲区就像一个窗口 - 当缓冲区被填满时,它会从头开始重写。因此,我们需要确保缓冲区足够大,以便我们可以在重写之前读取它。
这里有一个大问题 - 当垃圾收集器启动时,它会停止所有应用线程大约一秒钟 - 这足以让记录器将大约 100KB 的数据写入缓冲区(当使用 44100Hz 单声道 Pcm16bit 时),但在此期间我们没有读取,因为应用程序线程已停止!因此,如果缓冲区不够大,数据就会在我们有机会读取数据并将其写入文件之前被重写。因此,音频文件丢失了垃圾收集期间录制的音频。
因此,您需要使用足够大的 bufferSize 来初始化 AudioRecord
,以使其比垃圾回收事件的生命周期更长。对于不同的音频配置,这将是不同的大小。对我来说(使用 44100Hz、单声道、PCM16 位),缓冲区大小 512,000 就可以了。
我不确定 GC 在原生 Android 上是如何工作的,但我相信它可能是类似的。
关于android - AudioRecord 有时会跳过音频数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29233388/