- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一个布局,约有60个按钮,每一个,当按下,播放不同的音频文件。我的所有音频文件都作为MP3放在我的assets文件夹中,要播放它们,我基本上使用的代码与google ndk示例“native audio”项目中使用的代码相同:
https://github.com/googlesamples/android-ndk
我有10个相同的本机函数(只有唯一命名的变量)工作如下..
播放声音的功能:
jboolean Java_com_example_nativeaudio_Fretboard_player7play(JNIEnv* env, jclass clazz, jobject assetManager, jstring filename)
{
SLresult result;
// convert Java string to UTF-8
const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
assert(NULL != utf8);
// use asset manager to open asset by filename
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
assert(NULL != mgr);
AAsset* asset = AAssetManager_open(mgr, utf8, AASSET_MODE_UNKNOWN);
// release the Java string and UTF-8
(*env)->ReleaseStringUTFChars(env, filename, utf8);
// the asset might not be found
if (NULL == asset) {
return JNI_FALSE;
}
// open asset as file descriptor
off_t start, length;
int fd = AAsset_openFileDescriptor(asset, &start, &length);
assert(0 <= fd);
AAsset_close(asset);
// configure audio source
SLDataLocator_AndroidFD loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};
SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
SLDataSource audioSrc = {&loc_fd, &format_mime};
// configure audio sink
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSnk = {&loc_outmix, NULL};
// create audio player
const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME};
const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &p7PlayerObject, &audioSrc, &audioSnk,
3, ids, req);
assert(SL_RESULT_SUCCESS == result);
(void)result;
// realize the player
result = (*p7PlayerObject)->Realize(p7PlayerObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
(void)result;
// get the play interface
result = (*p7PlayerObject)->GetInterface(p7PlayerObject, SL_IID_PLAY, &p7PlayerPlay);
assert(SL_RESULT_SUCCESS == result);
(void)result;
if (NULL != p7PlayerPlay) {
// play
result = (*p7PlayerPlay)->SetPlayState(p7PlayerPlay, SL_PLAYSTATE_PLAYING);
assert(SL_RESULT_SUCCESS == result);
(void)result;
}
return JNI_TRUE;
}
void Java_com_example_nativeaudio_Fretboard_player7stop(JNIEnv* env, jclass clazz)
{
SLresult result;
// make sure the asset audio player was created
if (NULL != p7PlayerPlay) {
// set the player's state
result = (*p7PlayerPlay)->SetPlayState(p7PlayerPlay, SL_PLAYSTATE_STOPPED);
assert(SL_RESULT_SUCCESS == result);
(void)result;
// destroy file descriptor audio player object, and invalidate all associated interfaces
(*p7PlayerObject)->Destroy(p7PlayerObject);
p7PlayerObject = NULL;
p7PlayerPlay = NULL;
}
}
(*engineEngine)->CreateAudioPlayer()
。有没有什么方法可以改变音频播放器使用的audiosrc,而不必每次都从零开始销毁和重新创建它?
最佳答案
我们在同一条船上,我现在也在熟悉ndk和opensl es。我的答案是基于我的经验,完全由~2天的实验组成,因此可能会有更好的方法,但信息可能会帮助你的方式。
我有10个相同的本机函数(只有唯一命名的变量)工作如下..
如果我正确地理解了你的情况,你就不需要有重复的功能。在这些调用中唯一不同的是按下的按钮和最终要播放的声音,这可以通过jni调用作为参数传递。您可以将创建的播放器和数据存储在一个全局可访问的结构中,以便在需要停止/重播时检索它,可以使用buttonid作为映射的键。
[…]但我想最小化延迟,避免每次想播放不同的文件时都必须执行(*engineengine)->createAudioPlayer()。有没有什么方法可以改变音频播放器使用的audiosrc,而不必每次都从零开始销毁和重新创建它?
是的,不断地创建和销毁播放器是昂贵的,并且可能导致堆的碎片化(如opensl es 1.0规范中所述)。首先,我认为dynamicsourceitf允许您切换数据源,但似乎这个接口不打算像那样使用,至少在android 6上返回“feature unsupported”。
我怀疑为每个独特的声音创建一个播放器是一个很好的解决方案,特别是因为多次在彼此之上播放相同的声音(例如,在游戏中很常见)将需要任意数量的其他播放器来播放相同的声音。
缓冲队列
bufferqueues是播放器在播放时将处理的单个缓冲区的队列。当所有缓冲区都被处理后,播放器“停止”(虽然它的官方状态仍然是“播放”),但是只要新的缓冲区被排队,它就会恢复。
这允许你做的是创建尽可能多的播放器重叠的声音,你需要。当你想播放一个声音时,你要在这些播放机上迭代,直到找到一个当前没有处理缓冲区的播放机(BufferQueueItf->GetState(...)
提供了这个信息,或者可以注册一个回调,这样你就可以将播放机标记为“空闲的”)。然后,根据声音的需要将尽可能多的缓冲区放入队列,然后立即开始播放。
据我所知,缓冲队列的格式在创建时被锁定。因此,必须确保所有输入缓冲区的格式相同,或者为每个格式创建不同的缓冲队列(和播放器)。
Android简单缓冲队列
根据android ndk文档,bufferqueue接口在未来有望有重大变化。他们提取了一个具有bufferqueue大部分功能的简化接口,并将其命名为androidsimplebufferqueue。此接口不会更改,因此使您的代码更经得起未来的考验。
使用androidsimplebufferqueue松脱的主要功能是能够使用非pcm源数据,因此在使用之前必须对文件进行解码。这可以在opensl es中使用androidsimplebufferqueue作为接收器来完成。更新的api还支持使用mediacodec,它是ndk实现ndkmedia(查看本机编解码器示例)。
资源
ndk文档确实包含了一些在其他地方很难找到的重要信息。Here'sOpenSL ES特定页面。
它可能接近600页,难以消化,但OpenSL ES 1.0 Specification应该是您的主要信息来源。我强烈建议阅读第四章,因为它很好地概述了事情的运作方式。第三章有更多关于具体设计的信息。然后,我就使用搜索功能来阅读界面和对象。
了解OpenSL ES
一旦您理解了opensl工作原理的基本原理,它看起来就相当简单了。有媒体对象(播放器和记录器等)和数据源(输入)和数据接收器(输出)。实际上,您将一个输入连接到一个媒体对象,该媒体对象将处理的数据路由到其连接的输出。
源、汇和媒体对象都记录在规范中,包括它们的接口。有了这些信息,你真正需要做的就是挑选你需要的构建块,并将它们组合在一起。
2016年7月29日更新
从我的测试来看,bufferqueue和androidsimplebufferqueue似乎都不支持非pcm数据,至少在我测试过的系统(nexus 7@6.01,nvidia shield k1@6.0.1)上不支持,因此在使用之前需要对数据进行解码。
我试过使用ndk版本的mediaExtractor和mediacodec,但有几个注意事项:
MediaExtractor似乎无法正确返回使用加密解码所需的Uuid信息,至少对于我测试过的文件而言是这样。AMediaExtractor_getPsshInfo
返回anullptr
。
api并不总是表现为头声明中的注释。例如,通过检查返回的字节数而不是检查AMediaExtractor_advance
函数的返回值,检查mediaextractor中的eos(流的末尾)似乎是最可靠的。
我建议在解码过程中使用java,因为这些api更加成熟,测试也更加充分,而且您可能会从中获得更多的功能。一旦有了原始pcm数据的缓冲区,就可以将其传递给本机代码,从而减少延迟。
关于java - OpenSL ES无需重新创建音频播放器即可更改音频源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38092837/
我正在开发一个本地android项目,并尝试使用OpenSL播放一些音频效果。从VisualGDB提供的本地音频示例项目开始,我编写了以下代码。 在结尾附近,您可以看到我注释了一行,该行将名为hell
我一直在尝试为 Android 制作循环踏板。我有 1 条轨道运行良好。我想知道实现多个轨道需要什么样的资源/接口(interface)。我正在使用 OpenSL ES,并且我已经阅读了规范文档。 到
我正在编写一个 Android 应用程序,该应用程序需要能够以高精度查找大型 mp3 音频文件(约 90 分钟)中的特定点。 目前,我正在使用带有 URI 数据源的音频播放器对象的 OpenSL 方法
我一直致力于将 OpenSL 用于 Android 的低延迟音频应用。到目前为止,我在 Samsung Galaxy S5 上实现的最低延迟是 200 毫秒(触摸到声音,通过点击和记录点击声音,然后是
有没有办法让音频播放器输出到两个数据接收器? 更具体地说,我正在尝试使用将数据源设置为 uri 的音频播放器从网络流式传输 mp3 到缓冲区和输出混合。现在我将音频播放器的接收器设置为一个输出混合,所
我有一个布局,约有60个按钮,每一个,当按下,播放不同的音频文件。我的所有音频文件都作为MP3放在我的assets文件夹中,要播放它们,我基本上使用的代码与google ndk示例“native au
我正在尝试解决 Android OpenSLES 中的以下问题。 OpenSLES 规范说明如下: http://www.khronos.org/registry/sles/specs/OpenSL_
我们有一个使用低级 OpenSL ES 编写的带有移动音频客户端的应用程序,以实现麦克风的低延迟输入。比我们向服务器发送封装在 UDP 数据报中的 10ms 帧。 在服务器上,我们正在做一些后期处理,
当我在 Pixel 2(Oreo 8.0)上构建应用程序时,我得到PerformanceMode::LowLatency: 2019-06-30 15:04:15.560 8506-8506/? D/
我正在开发一个 Android 智能手机应用程序,它可以从麦克风输入语音并通过耳机输出语音。 但是,当我在麦克风中输入语音时,我被麦克风获取的语音音量从中间变得很小的现象所困扰。这是一种现象,如果您继
我需要一些有关 OpenSL ES 的帮助 - 我想改变 mp3 歌曲的音调。我使用的代码在这里:Android : How to change Playback Rate of music usin
我使用 NDK 创建了一个音频乐器,为了获得低延迟性能,我选择 OpenSL 来播放音乐文件。但我未能更改播放音乐的播放速率。这是快照代码: int OpenSLSoundPool::createOg
我对 NDK 和 OpenSL 很困惑我正在尝试将 OpenSL 添加到我的项目中。并且有一些问题。当我创建 ndk 项目时-我没有文件 Android.mk但我有 CMakeList 在教程中到处都
我是 opensl es 的新手。我目前正在试验 opensl es for android 的录制和播放功能。现在我有一个记录功能,可以将数据存储在缓冲区队列中。然后我可以播放缓冲区队列。谁能解释我
我试过 android NDK 中的 native 音频代码示例。当我尝试录制一些语音然后回放时效果很好。它使用主扬声器(扬声器)进行语音播放。我想修改代码,使语音在耳机而不是主扬声器中播放。有帮助吗
我开始用 C++ 实现我的游戏音频部分,我看到有 2 个可用的音频框架 AAudio ( https://developer.android.com/ndk/guides/audio/aaudio/a
我正在使用 MediaRecorder VOICE_CALL 音频源开发一个通话记录器应用程序,在一些棉花糖设备中它崩溃了,然后我将源更改为 MIC 这里传入的语音不是被记录下来。由于这个 java
自从我的 Galaxy S5 更新了 lolipop 后,我尝试在我的应用程序中修复通话录音。作为基础,我从这里使用谷歌示例项目:Sample . 这是代码的主要部分: AudioRecorder::
我在 android 8.1.0 中遇到了 opensl es 崩溃。 相关代码: TEResult SLESAudioEngine::release(TEMsg *pMsg) { TERes
我正在构建一个可以生成声音的应用程序(目前它主要是实验性的)并在 Android 手机上播放。 目前,我正在尝试播放简单的正弦波声音 (440 Hz),并首先尝试使用 Audiotrack,但遇到了一
我是一名优秀的程序员,十分优秀!