在OpenSL,Android上缓冲URI

时间:2014-07-15 12:22:33

标签: android audio android-ndk java-native-interface opensl

我已经尝试了几周的OpenSL。我通过SL_DATALOCATOR_URI作为源在sdcard上播放文件时尝试访问缓冲区。我想写一些自己的效果,需要缓冲区。

目前在代码中,我创建了两个音频播放器。一个是将文件读取到缓冲区,另一个是将缓冲区写入输出。当我用麦克风(录音机)测试代码时,一切都很好。声音输入按预期工作。

当我用uri audioplayer切换录音机时,队列变得混乱。 Streaming没有监听线程锁(它按照我的理解发生异步)并且缓冲区调用未正确触发,时间过得很快。

我已将日志放入每个方法,因此结果如下所示:

V/PDecoder( 1292): Position : 15023
V/PDecoder( 1292): Position : 16044
V/PDecoder( 1292): Position : 17043
V/PDecoder Native PL1( 1292): bqPlayerCallback
V/PDecoder Native PL1( 1292): Notify thread lock
V/PDecoder Native PL1( 1292): android_AudioIn 32768
V/PDecoder Native PL1( 1292): Wait thread lock
V/PDecoder Native PL1( 1292): android_AudioOut 32768
V/PDecoder Native PL1( 1292): android_AudioIn 32768
V/PDecoder Native PL1( 1292): android_AudioOut 32768
V/PDecoder Native PL1( 1292): Wait thread lock
V/PDecoder Native PL1( 1292): bqRecorderCallback
V/PDecoder Native PL1( 1292): Notify thread lock
V/PDecoder( 1708): Position : 18041
V/PDecoder( 1708): Position : 19040
V/PDecoder( 1708): Position : 20038

在队列回调被解雇之前,秒数就会消失。

所以问题是,我该如何纠正这个问题?有没有办法用于音频播放器&gt; <缓冲区> uri播放输出解决方案?我究竟做错了什么?如果有人能指出我正确的方向,我们非常感激。

代码在这里粘贴有点长,所以这里有要点

3 个答案:

答案 0 :(得分:1)

在我在问题代码中放弃自己之后,决定再次写一遍,尽可能干净。

我发现毕竟我没有锁定uri玩家。我在答案的最后添加了工作的最终代码。代码适合播放本地文件或url,但需要在从java开始的线程中运行,否则你将锁定gui线程。

PS。缓冲区正在使用堆栈,因此您可能希望将其移动到堆中,并可能将指针保存在结构中。此外,播放,暂停,销毁方法都没有完成。如果您想使用代码,您可以轻松实现这些功能。

奖金。代码还包括一个调用java实例方法的简单方法(没有从java部分发送的dreaded * env)。如果需要,请查看JNI_OnLoad,然后playStatusCallback(),然后callPositionChanged()方法。

代码在这里粘贴有点长,所以这里有要点

答案 1 :(得分:0)

艾拉,这是我现在为我的项目所遇到的确切问题。我一直关注这个博客:

http://audioprograming.wordpress.com/2012/10/29/lock-free-audio-io-with-opensl-es-on-android/

这是循环缓冲区的实现,来自同一个博客:

http://audioprograming.wordpress.com/2012/03/03/android-audio-streaming-with-opensl-es-and-the-ndk/

无论如何,在研究代码时,看起来他的openl-native h和c文件的版本名为opensl_io。他还有另一个类opensl_example,它有一个inbuffer和一个outbuffer,中间有一些简单的处理。看起来他的录音机对象填充了这个opensl_example类的inbuffer,他的outbuffer填充了他的audioplayer对象以播放下沉。听起来,你也是这样做的。

基本上,我试图用来自文件的输入流替换记录器对象,因为如果我想在流期间以不同的方式处理每个块,我必须能够从文件中访问块的缓冲区。你正在使用utf8转换的URI中的SLDATA_locator,我现在正尝试这样做,但我不确定如何从中获取流。

现在,博客示例的工作原理是它从流中的记录器对象获取音频输入,在填充时将其放入循环缓冲区,并将其通过处理输出。我试图用我的mp3缓冲区替换录音机缓冲区的来源。同样,听起来你的代码就是这样。音频编程博客的例子对我来说特别复杂,因为我对SWIG的工作方式并不完全确定。但是,既然您正在使用JNI,那可能会更容易。

你能告诉我你的工作方式吗?您是否只使用uri字符串作为参数调用StartPDecoderNative然后从Java调用DecodeOn?

答案 2 :(得分:0)

好的,尝试使用一个简单的java mainactivity来运行c和h代码,它按顺序运行这两个函数,单击按钮。

此外,看起来你在java中也需要一个positionchanged方法。你在那里跑步的是什么?我可以用jmethod评论该部分并播放音乐,以便它能够正常工作。是寻求吗?

最后,也许我只是在理解它时遇到了一些麻烦,但是你在哪个缓冲区进行处理,它在哪里?它是outbuffer吗?如果我只是想,或者只是将fft或者更多只是一个标量乘法输出到输出声音,我会在将它播放到最终接收器之前将其乘以outbuffer吗?