AudioRecord - 如何将数据输入缓冲区?

9
我正在使用AudioRecord类时遇到一些问题。我想要将录制的数据存储在缓冲区中,但是我不确定正确的方法是什么。我查看了大量的示例,但其中大多数都很复杂并且代表了许多不同的方法。我正在寻找一个简单的方法或简单的解释。
以下是我的项目音频设置:
int audioSource = AudioSource.MIC;
int sampleRateInHz = 8000;
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);

short[] buffer = new short[bufferSizeInBytes];

AudioRecord audioRecorder = new AudioRecord(audioSource,
                                            sampleRateInHz, 
                                            channelConfig, 
                                            audioFormat, 
                                            bufferSizeInBytes);

我正在尝试创建一个录音功能:

public void Recording() {
    audioRecorder.startRecording();
    ...
    audioRecorder.stop();
    audioRecorder.release();
}

我知道我应该使用 .read(short[] audioData, int offsetInShorts, int sizeInShorts) 函数。这时我的问题开始了。我不确定 audioData 缓冲区的工作原理 - 我假设函数将录制的样本放入 audioData 中。如果它已经完全填满数据会发生什么?它会从最早的位置开始重写吗?如果是,我相信我必须将所有收集到的样本复制到其他地方。这引发了另一个问题 - 我如何检查 .read(...) 函数缓冲区是否已满?我需要测量时间并复制缓冲区内容,还是有另一种方法可以实现?此外,我需要为整个录音操作创建一个线程吗?
对于在同一个主题中提出这么多问题我感到抱歉 :)
1个回答

4

您的问题的答案:

recorder.read(...) 并不一定读取任何数据。您可能需要重新编写循环,在调用 read 之间暂停一小段时间(例如 50ms)。它也不应该在缓冲区没有数据时将缓冲区排队。此外,由于缓冲区可能没有填满,您可能需要使用一种维护字节数计数的数据结构。ByteBuffer 是一个好的选择,您可以在 read 循环中将字节放入其中,当其足够充满时,将其排队传输并开始另一个。

当然,您需要创建一个线程来循环它。代码如下所示。

这是经过修改的记录循环版本,可进行适当的错误检查。它使用了一个 Queue<ByteBuffer> 而非 Queue<byte[]>:

private void startRecording() {

    recorder.startRecording();
    isRecording = true;
    recordingThread = new Thread(new Runnable() {

        @Override
        public void run() {
            bData = ByteBuffer.allocate(BufferElements);
            bbarray = new byte[bData.remaining()];
            bData.get(bbarray);
            while (isRecording) {

                int result = recorder.read(bbarray, 0, BufferElements);
                System.out.println("READ DATA");
                if (result > 0) {
                    qArray.add(bData);

                    --your stuffs--
                    bData = ByteBuffer.allocate(BufferElements);
                } else if (result == AudioRecord.ERROR_INVALID_OPERATION) {
                    Log.e("Recording", "Invalid operation error");
                    break;
                } else if (result == AudioRecord.ERROR_BAD_VALUE) {
                    Log.e("Recording", "Bad value error");
                    break;
                } else if (result == AudioRecord.ERROR) {
                    Log.e("Recording", "Unknown error");
                    break;
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    break;
                }
            }
        }
    }, "AudioRecorder Thread");
    recordingThread.start();
}

当然,你需要在某个地方调用recorder.startRecording()才能获取任何数据。

如果需要一个工作示例,请查看此示例


这里的qArray是什么? - OnePunchMan
可能是ArrayList。我现在不记得了。最好参考这个例子https://dev59.com/_Goy5IYBdhLWcg3wg-Um#13487250。 - Rahul Baradia

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