OpenSL ES: OpenSL ES 简介

1. OpenSL ES 是什么html

OpenSL ES (Open Sound Library for Embedded Systems)是无受权费、跨平台、针对嵌入式系统精心优化的硬件音频加速API。它为嵌入式移动多媒体设备上的本地应用程序开发者提供标准化, 高性能,低响应时间的音频功能实现方法,并实现软/硬件音频性能的直接跨平台部署,下降执行难度,促进高级音频市场的发展。简单来讲OpenSL ES是一个嵌入式跨平台免费的音频处理库。
Android的OpenSL ES库是在NDK的platforms文件夹对应android平台先相应cpu类型里面,如:
android

2. OpenSL ES 与 Android的关系网络

Android 2.3 (API 9) 即开始支持 OpenSL ES 标准了,经过 NDK 提供相应的 API 开发接口,下图是 Android 官方给出的关系图(参考:https://source.android.com/devices/audio/latency_app.html):app

由该图能够看出,Android 实现的 OpenSL ES 只是 OpenSL 1.0.1 的子集,而且进行了扩展,所以,对于 OpenSL ES API 的使用,咱们还须要特别留意哪些是 Android 支持的,哪些是不支持的,具体相关文档的地址位于 NDK docs 目录下:async

NDKroot/docs/Additional_library_docs/opensles/index.html
NDKroot/docs/Additional_library_docs/opensles/OpenSL_ES_Specification_1.0.1.pdf

3. 与Java层的AudioRecord, AudioTrack的关系函数

利用 Android 提供的 AudioRecord 采集音频,利用 AudioTrack 播放音频,利用 MediaCodec 来编解码,这些 API 均是 Android 提供的 Java 层 API,不管是采集、播放仍是编解码,这些 API 接口都须要将音频数据从 Java 拷贝到 native 层,或者从 native 层拷贝到 Java,若是但愿减小拷贝,开发更加高效的 Android 音频应用,则建议使用 Android NDK 提供的 OpenSL ES API 接口,它支持在 native 层直接处理音频数据。性能

4. OpenSL ES的特性以及优劣势学习

特性:优化

1)C 语言接口,兼容 C++,须要在 NDK 下开发,能更好地集成在 native 应用中
(2)运行于 native 层,须要本身管理资源的申请与释放,没有 Dalvik 虚拟机的垃圾回收机制
(3)支持 PCM 数据的采集,支持的配置:16bit 位宽,16000 Hz采样率,单通道。(其余的配置不能保证兼容全部平台)
(4)支持 PCM 数据的播放,支持的配置:8bit/16bit 位宽,单通道/双通道,小端模式,采样率(8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 Hz)
(5)支持播放的音频数据来源:res 文件夹下的音频、assets 文件夹下的音频、sdcard 目录下的音频、在线网络音频、代码中定义的音频二进制数据等等

优点:ui

1)避免音频数据频繁在 native 层和 Java 层拷贝,提升效率
(2)相比于 Java API,能够更灵活地控制参数
(3)因为是 C 代码,所以能够作深度优化,好比采用 NEON 优化
(4)代码细节更难被反编译

劣势:

1)不支持版本低于 Android 2.3 (API 9) 的设备
(2)没有所有实现 OpenSL ES 定义的特性和功能
(3)不支持 MIDI 
(4)不支持直接播放 DRM 或者 加密的内容
(5)不支持音频数据的编解码,如需编解码,须要使用 MediaCodec API 或者第三方库
(6)在音频延时方面,相比于上层 API,并无特别明显地改进

5. OpenSL ES的一些基本概念

Objects和Interfaces

OpenSL ES 有两个必须理解的概念,就是 Object 和 Interface,Object 能够想象成 Java 的 Object 类,Interface 能够想象成 Java 的 Interface,但它们并不彻底相同,下面进一步解释他们的关系:
(1) 每一个 Object 可能会存在一个或者多个 Interface,官方为每一种 Object 都定义了一系列的 Interface
(2)每一个 Object 对象都提供了一些最基础的操做,好比:Realize,Resume,GetState,Destroy 等等,若是但愿使用该对象支持的功能函数,则必须经过其 GetInterface 函数拿到 Interface 接口,而后经过 Interface 来访问功能函数
(3)并非每一个系统上都实现了 OpenSL ES 为 Object 定义的全部 Interface,因此在获取 Interface 的时候须要作一些选择和判断

全部的Object在OpenSL里面咱们拿到的都是一个SLObjectItf:

struct SLObjectItf_ {
    SLresult (*Realize) (SLObjectItf self,SLboolean async);

    SLresult (*Resume) (SLObjectItf self,SLboolean async);

    SLresult (*GetState) (SLObjectItf self,SLuint32 * pState);

    SLresult (*GetInterface) (SLObjectItf self, const SLInterfaceID iid, void * pInterface);

    SLresult (*RegisterCallback) (SLObjectItf self, slObjectCallback callback, void * pContext);

    void (*AbortAsyncOperation) (SLObjectItf self);

    void (*Destroy) (SLObjectItf self);

    SLresult (*SetPriority) (SLObjectItf self, SLint32 priority, SLboolean preemptable);

    SLresult (*GetPriority) (SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable);

    SLresult (*SetLossOfControlInterfaces) (SLObjectItf self, SLint16 numInterfaces, SLInterfaceID * pInterfaceIDs, SLboolean enabled);
};

typedef const struct SLObjectItf_ * const * SLObjectItf;

这里的SLObjectItf是一个二级指针,它指向的是一个结构体指针。任何建立出来的Object都必须调用 Realize 方法作初始化,在不须要的时候可使用 Destroy 方法来释放资源。

Interface则是方法的集合,例如SLRecordItf里面包含了和录音相关的方法,SLPlayItf包含了和播放相关的方法。咱们功能都是经过调用Interfaces的方法去实现的,如 SLEngineItf 这个interface,咱们能够经过它去建立各类Object,例如播放器、录音器、混音器的Object,而后在用这些Object去获取各类Interface去实现各类功能。

struct SLEngineItf_ {
    SLresult (*CreateAudioPlayer) (SLEngineItf self, SLObjectItf * pPlayer, SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired);

    SLresult (*CreateAudioRecorder) (SLEngineItf self, SLObjectItf * pRecorder, SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired);

    SLresult (*CreateOutputMix) (SLEngineItf self, SLObjectItf * pMix, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired);

    ...
};

6. OpenSL ES的基本开发流程

这里以使用OpenSL ES 来播放一个PCM文件为例,主要包括:

1、 建立接口对象
2、设置混音器
3、建立播放器(录音器)
4、设置缓冲队列和回调函数
5、设置播放状态
6、启动回调函数

因为OpenSL ES是Native层提供的API,在使用前须注意添加头文件和连接选项,在须要用到OpenSL ES API的C文件中添加:

#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

连接库文件:

若是是:Android.mk

LOCAL_LDLIBS += -lOepnSLES

若是是:CMakeLists.txt

 在 target_link_libraries 括号中添加 OpenSLES 

示例代码: 《OpenSL ES: 利用OpenSL ES播放一个存在于SDcard上的PCM文件

参考连接:

1. Android音频开发(7):使用 OpenSL ES API(下)

2. OpenSL ES 学习笔记

3.Android OpenSL ES 开发:Android OpenSL 介绍和开发流程说明

相关文章
相关标签/搜索