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

栏目: Android · 发布时间: 6年前

内容简介:翻译自Android Extensions针对Android的OpenSL ES扩展了参考OpenSL ES规范,使其与Android兼容,并利用Android平台的强大功能和灵活性。Android扩展的API定义在

翻译自Android Extensions

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

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

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

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

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音频流类型的示例:

// 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.
复制代码

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

// ... 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效果扩展。

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
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指南-编程注意事项


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

机器学习实战

机器学习实战

Peter Harrington / 李锐、李鹏、曲亚东、王斌 / 人民邮电出版社 / 2013-6 / 69.00元

机器学习是人工智能研究领域中一个极其重要的研究方向,在现今的大数据时代背景下,捕获数据并从中萃取有价值的信息或模式,成为各行业求生存、谋发展的决定性手段,这使得这一过去为分析师和数学家所专属的研究领域越来越为人们所瞩目。 本书第一部分主要介绍机器学习基础,以及如何利用算法进行分类,并逐步介绍了多种经典的监督学习算法,如k近邻算法、朴素贝叶斯算法、Logistic回归算法、支持向量机、AdaB......一起来看看 《机器学习实战》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具