3

我想做的是录制一个声音,处理它就像为录制的音频添加一些效果,然后使用opensl尽可能快地重放它。我很难在网上找到关于做这样的事情的信息,所以我实际上有几个问题。

我查看了 android 原生音频示例,以及以 android ndk 开头的书,这让我开始使用 opensl,但它们并没有真正帮助我很好地理解录音。

1)首先,要立即播放录制的音频,我是否能够从播放音频的线程中读取缓冲区,同时录制线程正在写入缓冲区?我知道有人可能会为这个想法发疯,因为同时通过两个不同的线程访问内存中的某个对象的想法可能会导致问题,但如果确保记录线程总是在之前写入内存播放音频线程,那有可能吗?

2)或者实时回放,我会使用带有两个或三个非常小的缓冲区的缓冲区队列,并且每次填充一个缓冲区时都会调用一个回调,然后在下一个缓冲区被录制填充时播放该缓冲区音频线程?但我正在阅读,有人说回调并不总是被调用(我发现的最有用的链接是:https ://groups.google.com/forum/#!msg/android-ndk/hLSygQrmcPI/qtwB76JNa_EJ ) . 另外,这意味着录制的音频和播放的音频之间的时间差将是缓冲区的大小加上回调让录制对象知道使用下一个缓冲区开始录制所需的时间。我认为录音机停止录音和重新开始录音之间会有一个差距。

3) android 录制缓冲区队列也是我理解问题的地方。我必须在android中使用缓冲区队列来录制音频吗?或者是否可以在不使用缓冲区队列的情况下直接记录到缓冲区?我对此有疑问,因为明确的方法SLAndroidSimpleBufferQueueItf实际上似乎不起作用。显然它是一个错误。而且我似乎无法在缓冲区已填充数据后对其进行记录。由于 clear 方法似乎不起作用,我如何告诉记录器要记录到队列中的哪个缓冲区?

我知道这有很多问题要问,而且我没有说出我尝试过的所有内容,但我希望有人对此有一些经验,可以为我和其他任何在回放录制时遇到问题的人提供一些启示使用opensl实时音频。

4

2 回答 2

5

我几乎完全找到了我正在寻找的东西。实时回放录制的音频的一种方法是使用称为循环缓冲区(或循环缓冲区)的东西,基本上将录制的音频读入其中,而回放的音频读取所有内容,直到录制的音频正在写入。

http://audioprograming.wordpress.com/

Android 中的 OpenSL ES 仍然不完全支持“Low-latency”,因为仍然有一点延迟,但它仍然工作得很好,只是听起来更像是一个轻微的回声

于 2013-01-14T14:35:59.803 回答
1

我意识到这已经得到回答,这是一个老问题。但是,为了澄清,在我的播放队列中,我不使用Clear(). GetState(state)我只是停止播放,然后通过循环使用等待队列耗尽,如下所示:

SLresult res;
SLAndroidSimpleBufferQueueState state = {0};
res = (*playbackBufferQueue)->GetState(playbackBufferQueue, &state);

while (state.count && (res == SL_RESULT_SUCCESS))  
{  
    prevState = state;
    res = (*m_playbackBufferQueue)->GetState(m_playbackBufferQueue, &state); 
    // Otherwise this will peg the CPU
    sleep(1);
}

为了支持低延迟,您可以使用从 Android 查询的“最佳”速率和样本大小。您可以使用本机 API 调用来做到这一点吗?当然不是,别傻了。在 Java 中执行并将其传递回本机:

int getBestPlaybackRate() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        return Integer.parseInt(audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
    }
    return 0;
}
int getBestBufferSize() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        return Integer.parseInt(audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER));
    }
    return 0;
}
于 2017-03-16T19:22:59.723 回答