如何正确停止Android openSLES录音机?

时间:2014-08-06 23:58:03

标签: android android-ndk audiorecord opensl

我在Android中使用openSLES的原生录音机。记录器工作,但是当调用stop方法时,它似乎继续写缓冲区,因为我继续获取日志:

...
08-07 01:36:43.229: V/AudioRecord(6194): Overrun user: 61400, server: 61c00, flags 0001
08-07 01:36:43.239: V/AudioRecord(6194): Overrun user: 61400, server: 61c00, flags 0001
08-07 01:36:43.249: V/AudioRecord(6194): Overrun user: 61400, server: 61c00, flags 0001
...

我正在使用线程锁定方法来记录缓冲区,但为什么我在停止录制器后获取这些日志,如下所示:

typedef struct opensl_stream {
...
  SLObjectItf recorderObject;
  SLRecordItf recorderRecord;
  SLAndroidSimpleBufferQueueItf recorderBufferQueue;
...
} OPENSL_STREAM;

OPENSL_STREAM  *p;
//starting recorder
...
//stopping recorder
if (p->recorderObject != NULL) {
    (*p->recorderObject)->Destroy(p->recorderObject);
    p->recorderObject = NULL;
    p->recorderRecord = NULL;
    p->recorderBufferQueue = NULL;
  }

在尝试如上所述停止录像机之后,我仍然得到AudioRecord(6194): Overrun user日志,这意味着缓冲区被读取但未被使用。如何正确停止录制?

1 个答案:

答案 0 :(得分:2)

首先,你应该在摧毁它之前停止录音机,但这还不够。

由于从自己的线程调用OpenSL回调,因此从另一个线程停止记录并不意味着所有回调都会立即停止。 (或者不会调用新的回调。)因此,您必须“计算”您排队的缓冲区数量,因此在回调中您可以计算处理的回调数量。

所以伪代码看起来像这样:

  • 通过将记录状态设置为SL_RECORDSTATE_STOPPED来停止记录器,不要将更多缓冲区队列排入队列。
  • 等待所有排队的缓冲区队列都通过检查您的计数器来处理。
  • 销毁录像机,释放回调可能使用的其他资源(内存)。

当排队缓冲区时,并且在opensl回调结束时,您必须以线程安全的方式自己计算排队/处理的缓冲区队列。

您可以在等待所有处理过程中使用pthread互斥/条件/广播。 (或者你可以使用一个简单的while循环,其中一些在里面睡觉。)