安卓音频录音类——快速处理直播麦克风音频,设置回调功能

我想从麦克风录制音频并访问它,以便近乎实时地播放。我不确定如何使用Android AudioRecord类来录制一些麦克风音频并快速访问它。

对于AudioRecord类,官方网站上说“应用程序及时轮询AudioRecord对象”,“正在填充的缓冲区的大小决定了在过度运行未读数据之前录制的时间长度”。后来建议在轮询频率较低时使用更大的缓冲区。他们从未真正在代码中展示过示例。

我在一本书中看到的一个例子使用AudioRecord类连续读取新填充的实时麦克风音频的缓冲区,然后应用程序将此数据写入SD文件。伪代码看起来像这样 -

set up AudioRecord object with buffer size and recording format info
set up a file and an output stream
myAudioRecord.startRecording();
while(isRecording)
{
    // myBuffer is being filled with fresh audio
    read audio data into myBuffer
    send contents of myBuffer to SD file
}
myAudioRecord.stop();

此代码如何将其读取与记录速率同步尚不清楚 - 布尔值“isRecording”是否在其他地方正确排序?似乎这段代码可能读取得太频繁或太不频繁,这取决于读取和写入所需的时间。

该网站文档还说,AudioRecord类有一个名为OnRecordPositionUpdateListener的嵌套类,它被定义为一个接口。该信息表明,您以某种方式指定了要通知录制进度的时间段以及事件处理程序的名称,并且以指定的频率自动调用事件处理程序。我认为在伪代码中的结构是这样的 -

set target of period update message = myListener
set period to be about every 250 ms
other code

myListener()
{
    if(record button was recently tapped)
        handle message that another 250 ms of fresh audio is available
        ie, read it and send it somewhere
)

我需要找到一些特定的代码,这些代码允许我捕获和处理延迟小于约500 ms的麦克风音频。Android提供了另一个名为MediaRecorder的课程,但它不支持流媒体,我可能希望通过Wi-Fi网络近乎实时地流式传输实时麦克风音频。在哪里可以找到一些具体的例子?


答案 1

在对通知和一系列其他技术进行了大量实验之后,我确定了这段代码:

private class AudioIn extends Thread { 
     private boolean stopped    = false;

     private AudioIn() { 

             start();
          }

     @Override
     public void run() { 
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
            AudioRecord recorder = null;
            short[][]   buffers  = new short[256][160];
            int         ix       = 0;

            try { // ... initialise

                  int N = AudioRecord.getMinBufferSize(8000,AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT);

                   recorder = new AudioRecord(AudioSource.MIC,
                                              8000,
                                              AudioFormat.CHANNEL_IN_MONO,
                                              AudioFormat.ENCODING_PCM_16BIT,
                                              N*10);

                   recorder.startRecording();

                   // ... loop

                   while(!stopped) { 
                      short[] buffer = buffers[ix++ % buffers.length];

                      N = recorder.read(buffer,0,buffer.length);
                      //process is what you will do with the data...not defined here
                      process(buffer);
                  }
             } catch(Throwable x) { 
               Log.w(TAG,"Error reading voice audio",x);
             } finally { 
               close();
             }
         }

      private void close() { 
          stopped = true;
        }

    }

到目前为止,它在我尝试过的六款Android手机上都非常强大。


答案 2

我想知道您是否可以通过以下方式将这些答案组合在一起...

在 while 循环之前使用 setPositionNotificationPeriod(160)。这应导致每次读取 160 帧时调用回调。与其在执行读取循环的线程内部调用 process(buffer),不如从回调调用 process(buffer)。使用变量跟踪上次读取缓冲区,以便处理正确的缓冲区。就像现在一样,你阻止了读取,然后在处理时你没有读取。我认为最好将这两者分开。


推荐