适用于Android的OpenSL ES指南-OpenSL ES的Android扩展

翻译自Android Extensionshtml

针对Android的OpenSL ES扩展了参考OpenSL ES规范,使其与Android兼容,并利用Android平台的强大功能和灵活性。android

Android扩展的API定义在OpenSLES_Android.h和它包含的头文件中。查阅OpenSLES_Android.h了解这些扩展的详细信息。这个文件位于您的安装根目录下,在sysroot/usr/include/SLES目录下。除非另有说明,全部接口都是显式的。ios

这些扩展限制了应用程序到其余OpenSL ES实现的可移植性,由于它们是特定于android的。您能够经过避免使用扩展或使用#ifdef在编译时排除它们来缓解这个问题。git

下表显示了Android特定的接口和数据定位器及Android OpenSL ES支持的每种对象类型。单元格中的Yes值表示对象类型均可用的接口和数据定位器data locators。github

Feature Audio player Audio recorder Engine Output mix
Android buffer queue Yes: Source (decode) No No No
Android configuration Yes Yes No No
Android effect Yes No No Yes
Android effect capabilities No No Yes No
Android effect send Yes No No No
Android simple buffer queue Yes: Source (playback) or sink (decode) Yes No No
Android buffer queue data locator Yes: Source (decode) No No No
Android file descriptor data locator Yes: Source No No No
Android simple buffer queue data locator Yes: Source (playback) or sink (decode) Yes: Sink No No

Android配置接口

Android配置界面提供了一种为对象设置特定于平台的参数的方法。该接口不一样于其余OpenSL ES 1.0.1接口,由于您的应用程序能够在实例化相应对象以前使用它;并且,您能够在实例化对象以前配置它。OpenSLES_AndroidConfiguration.h头文件,驻留在/sysroot/usr/include/SLES中,记录了如下可用的配置键值:编程

  • 音频播放器的流类型(默认SL_ANDROID_STREAM_MEDIA)。
  • 音频记录器的记录配置文件(默认SL_ANDROID_RECORDING_PRESET_GENERIC)。

下面的代码片断展现了如何在音频播放器上设置Android音频流类型的示例:api

// CreateAudioPlayer and specify SL_IID_ANDROIDCONFIGURATION
// in the required interface ID array. Do not realize player yet.
// ...
SLAndroidConfigurationItf playerConfig;
result = (*playerObject)->GetInterface(playerObject,
    SL_IID_ANDROIDCONFIGURATION, &playerConfig);
assert(SL_RESULT_SUCCESS == result);
SLint32 streamType = SL_ANDROID_STREAM_ALARM;
result = (*playerConfig)->SetConfiguration(playerConfig,
    SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
assert(SL_RESULT_SUCCESS == result);
// ...
// Now realize the player here.
复制代码

可使用相似的代码来配置音频记录器的预设:bash

// ... obtain the configuration interface as the first four lines above, then:
SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
result = (*playerConfig)->SetConfiguration(playerConfig,
    RECORDING_PRESET, &presetValue, sizeof(SLuint32));
复制代码

Android effects interfaces 效果接口

Android的效果、效果发送和效果功能接口为应用程序查询和使用特定于设备的音频效果提供了通用机制。设备制造商应该记录他们提供的任一设备特定的音频效果。网络

便携应用应该使用OpenSL ES 1.0.1 api来实现音频效果,而不是Android效果扩展。ide

Android file descriptor data locator 文件描述符数据定位器

Android文件描述符数据定位器容许您将音频播放器的源指定为具备读权限的开放文件描述符。数据格式必须是MIME。

这个扩展与native asset manager结合使用特别有用,由于应用程序经过文件描述符从APK读取assets。

Android simple buffer queue data locator and interface 简单的缓冲队列数据定位器和接口

在OpenSL ES 1.0.1参考规范中,缓冲区队列只能用于音频播放器,它们与PCM和其余数据格式兼容。Android简单缓冲队列数据定位器和接口规范与参考规范相同,但有两个例外:

  • 您可使用带有录音机和音频播放器的Android简单缓冲队列。
  • 您只能对这些队列使用PCM数据格式。

为了记录,您的应用程序应该排队空缓冲区。当一个注册回调发送一个通知,系统已经写完数据到缓冲区,应用程序能够从缓冲区读取。

回放以一样的方式工做。可是,为了未来的源代码兼容性,咱们建议应用程序使用Android简单缓冲区队列,而不是OpenSL ES 1.0.1缓冲区队列。

buffer queue缓冲队列行为

Android实现不包括引用规范的要求,即当回放进入SL_PLAYSTATE_STOPPED状态时,播放cursor返回到当前播放缓冲区的开始位置。该实现能够顺应该行为,也能够保持播放cursor的位置不变。所以,您的应用程序不能假定这两种行为都发生了。所以,在转换到SL_PLAYSTATE_STOPPED以后,应该显式调用BufferQueue::Clear()方法。这样作将缓冲区队列设置为已知状态。

相似地,缓冲区队列回调的触发器是否必须转换为SL_PLAYSTATE_STOPPED或执行BufferQueue::Clear(),也没有规范来控制。所以,咱们建议您不要对其中一个建立依赖关系;相反,你的应用程序应该可以同时处理这两种状况。

对象建立时的动态接口

为了方便起见,OpenSL ES 1.0.1的Android实现容许应用程序在实例化对象时指定动态接口。这是使用DynamicInterfaceManagement::AddInterface()的替代方案,以便在实例化后添加这些接口。

扩展报告 有三种方法能够查询平台是否支持Android扩展。以下:

  • Engine::QueryNumSupportedExtensions()
  • Engine::QuerySupportedExtension()
  • Engine::IsExtensionSupported()

这些方法都返回ANDROID_SDK_LEVEL_<API-level>,其中API-level是平台API级别;例如,ANDROID_SDK_LEVEL_23。平台API级别为9或更高意味着平台支持扩展。

解码音频为PCM格式

本节描述了OpenSL ES 1.0.1中一个不同意使用的android专用扩展,用于将编码流解码到PCM,而无需当即回放。下表给出了使用此扩展和替代方案的建议。

API level Alternatives替代方案
15 及如下 一种具备适当许可证的开源编解码器
16 到 20 MediaCodec类或具备适当许可证的开源编解码器
21 以上 NDK MediaCodec在<media/NdkMedia*.>头文件,MediaCodec类,或具备适当许可证的开源编解码器

注意:目前没有关于MediaCodec API的NDK版本的文档。可是,您能够参考natvie-codec示例代码。

标准音频播放器回放音频设备,指定输出混合做为数据接收器。Android扩展的不一样之处在于,若是应用程序将数据源指定为URI或使用MIME数据格式描述的Android文件描述符数据定位器,那么音频播放器将充当解码器。在这种状况下,数据接收器是一个使用PCM数据格式的Android简单缓冲队列数据定位器。

这个特性主要用于游戏在转换到新的游戏级别时预加载它们的音频assets,这与SoundPool类提供的功能相似。

应用程序最初应该在Android简单缓冲区队列中加入一组空缓冲区。而后,应用程序用PCM数据填充缓冲区。Android简单的缓冲区队列回调在每一个缓冲区被填满后触发。回调处理程序处理PCM数据,从新装入如今为空的缓冲区,而后返回。应用程序负责跟踪解码缓冲区(buffer);回调参数列表不包含足够的信息来指示包含数据的缓冲区或接下来应该加入队列的缓冲区。

数据源经过在流的末尾传递SL_PLAYEVENT_HEADATEND事件隐式地报告流的结束(EOS)。当应用程序解码了它接收到的全部数据后,它就再也不调用Android简单缓冲队列回调。

数据槽sink的PCM数据格式一般与编码的数据源在采样率、声道数和位深度方面匹配。可是,您能够解码到不一样的采样率、声道数或位深度。有关检测实际PCM格式的规定的信息,请看下面的经过元数据肯定解码PCM数据的格式部分

OpenSL ES为Android的PCM解码功能,支持暂停和初始搜索;它不支持音量控制、效果、循环或播放速率。

根据平台实现的不一样,解码可能须要不能闲置的资源。所以,咱们建议您确保提供足够数量的空PCM缓冲区;不然,解码器将挨饿。这可能发生,例如,若是您的应用程序从Android简单的缓冲区队列回调返回,而不排队另外一个空缓冲区。解码器饿死的结果是未知的,但可能包括:删除解码PCM数据,暂停解码过程,或完全终止解码器。

注意:对于运行在Android 4.x (API级别16-20)上的应用程序,解码一个编码流到PCM,但不当即回放,咱们建议使用MediaCodec类。对于在Android 5.0 (API level 21)或更高版本上运行的新应用程序,咱们建议使用NDK等效程序<NdkMedia*.h>。这些头文件驻留在安装根目录下的media/目录中。

解码流式ADTS AAC转为PCM

若是数据源是使用MIME数据格式的Android缓冲队列数据定位器,而数据接收器是使用PCM数据格式的Android简单缓冲队列数据定位器,则音频播放器充当流解码器。配置MIME数据格式以下:

  • 容器:SL_CONTAINERTYPE_RAW
  • MIME类型字符串:SL_ANDROID_MIME_AACADTS

该特性主要用于流媒体应用程序,这些应用程序处理AAC音频,但须要在回放以前执行定制的音频处理。大多数须要将音频解码到PCM的应用程序应该使用解码音频到PCM所描述的方法,由于该方法更简单,能够处理更多的音频格式。这里描述的技术是一种更专业的方法,只有在这两种条件都适用时才会使用:

  • 压缩音频源是包含在ADTS头文件中的AAC帧流。
  • 应用程序管理这个流。数据不位于标识符为URI的网络资源中,也不位于标识符为文件描述符的本地文件中。

应用程序最初应该在Android缓冲区队列中加入一组已填充的缓冲区。每一个缓冲区包含一个或多个完整的ADTS AAC帧。每一个缓冲区清空后,Android缓冲区队列回调会触发。回调处理程序应该从新填充缓冲区并从新排队,而后返回。应用程序不须要跟踪已编码的缓冲区;回调参数列表包含足够的信息来指示下一个应该加入队列的缓冲区。流的末尾经过对EOS项进行排队显式地标记。EOS后,不容许再排队。

咱们建议您确保提供完整的ADTS AAC缓冲区,以免使解码器挨饿。这可能发生,例如,若是您的应用程序从Android buffer queue回调返回,而不排队另外一个完整的缓冲区。解码器饿死的结果是未知的。

除了数据源以外,流解码方法与解码音频到PCM的方法相同。

虽然名称类似,但Android缓冲队列与Android简单缓冲队列不一样。流解码器使用两个缓冲队列:ADTS AAC数据源的Android缓冲队列和PCM数据槽的Android简单缓冲队列。有关Android缓冲队列API的更多信息,请参阅安装根目录下docs/Additional_library_docs/openmaxal/目录中的index.html文件。

经过元数据肯定已解码的PCM数据的格式

SLMetadataExtractionItf接口是参考规范的一部分。可是,指示解码PCM数据的实际格式的元数据键是Android特有的。OpenSLES_AndroidMetadata.h头文件定义了这些元数据键。这个头文件驻留在安装根目录下/sysroot/usr/include/SLES目录中。

Object::Realize()方法执行完以后,元数据键索引当即可用。可是,在应用程序解码第一个编码数据以前,关联的值是不可用的。一个好的实践是,在调用Object::Realize方法后查询主线程中的键索引,在第一次调用时读取Android简单缓冲队列回调处理程序中的PCM格式元数据值。有关使用这个接口的示例,请参阅NDK包中的示例代码

元数据键名是稳定的,可是键索引没有被记录,而且可能会发生更改。应用程序不该假定索引在不一样的阶段运行中是持久的,也不该假定多个对象实例在同一过程运行中共享索引。

浮点型数据

在Android 5.0 (API level 21)及更高版本上运行的应用程序能够以单精度、浮点型向AudioPlayer提供数据。

在如下示例代码中,Engine::CreateAudioPlayer()方法建立一个使用浮点数据的音频播放器:

#include <SLES/OpenSLES_Android.h>
...
SLAndroidDataFormat_PCM_EX pcm;
pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
pcm.numChannels = 2;
pcm.sampleRate = SL_SAMPLINGRATE_44_1;
pcm.bitsPerSample = 32;
pcm.containerSize = 32;
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
...
SLDataSource audiosrc;
audiosrc.pLocator = ...
audiosrc.pFormat = &pcm;
复制代码

在音频采样页上阅读关于浮点音频的更多信息。


下一篇: 适用于android的OpenSL ES指南-编程注意事项

相关文章
相关标签/搜索