本文是我的《Android音频开发》系列的第七篇文章,上一篇文章总整体上介绍了 Android OpenSL ES API 的基本概况,告诉了大家这个框架有什么特性,可以做什么,不能做什么。本文则重点介绍 OpenSL ES 框架及其API接口的一些关键的设计和概念,只有理解了它们,你才能更好地读懂 OpenSL ES 的相关代码。示例代码则放到了文章的最后,相信大家理解了这些基本的概念后,就能很容易地读懂这些代码的细节了。

1. 面向对象的 C 语言接口

OpenSL ES 虽然是 C 语言编写,但是它的接口采用的是面向对象的方式,并不是提供一系列的函数接口,而是以 Interface 的方式来提供 API,这是理解 OpenSL ES API 的一个比较重要的点。

可能这么说比较抽象,举例来说,一般的 C 语言库,比如:math 库,提供的接口可能是这样的:

double cosh(double);

double sinh(double);

double tanh(double);

我们直接在代码中调用这个函数即可,但是 OpenSL ES 却不是这样提供 API 的,它的大都数 API 需要这样访问:

// 下面代码是对 Audio Engine 对象进行 “初始化”

SLEngineItf engineObject;

SLresult result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);

由此可见,OpenSL ES 的 API 大都数是通过 “对象” 来调用的,如果在 Android NDK 下开发过 C 代码,就应该不会太陌生,因为我们调用 “JNI* env” 的函数也是这个样子去调用的。

2. 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 的时候需要做一些选择和判断

通过查看 “OpenSLES.h” 文件,我们可以看到 OpenSL ES 定义的所有 Object 对象的 ID,我们可以通过 Object ID 来创建对应的对象实例。

其中,我们比较常用的应该就是:ENGINE、AUDIOPLAYER 和 AUDIORECORDER 对象了。

同样,“OpenSLES.h” 文件中还定义了所有的 Interface ID,通过 Interface ID 我们可以从对象中获取到对应的功能接口。

3. OpenSL ES 的状态机制

OpenSL ES 还有一个比较重要的概念,就是它的状态机制,如图所示:

任何一个 OpenSL ES 的对象,创建成功后,都进入 SL_OBJECT_STATE_UNREALIZED 状态,这种状态下,系统不会为它分配任何资源,直到调用 Realize 函数为止。

Realize 后的对象,就会进入 SL_OBJECT_STATE_REALIZED 状态,这是一种“可用”的状态,只有在这种状态下,对象的各个功能和资源才能正常地访问。

当一些系统事件发生后,比如出现错误或者 Audio 设备被其他应用抢占,OpenSL ES 对象会进入 SL_OBJECT_STATE_SUSPENDED 状态,如果希望恢复正常使用,需要调用 Resume 函数。

当调用对象的 Destroy 函数后,则会释放资源,并回到 SL_OBJECT_STATE_UNREALIZED 状态。

简言之,一个 OpenSL ES 对象的生命周期,就是从 create 到 destroy 的过程,生命周期的控制,都是通过开发者显示调用来完成的。

4. 常用的对象和结构体

心中保持一个概念,就是在 OpenSL ES 中,一切 API 的访问和控制都是通过 Interface 来完成的,连 OpenSL ES 里面的 Object 也是通过 SLObjectItf Interface 来访问和使用的。

4.1 Engine Object 和 SLEngineItf Interface

OpenSL ES 里面最核心的对象就是:Engine Object,音频引擎对象,它主要提供如下两个功能:

(1)管理 Audio Engine 的生命周期

(2)提供管理接口: SLEngineItf,该接口可以用来创建所有其他的 Object 对象

(3)提供设备属性查询接口:SLEngineCapabilitiesItf 和 SLAudioIODeviceCapabilitiesItf,这些接口可以查询设备的一些属性信息

Engine Object 对象的创建方法如下:

SLObjectItf engineObject;

slCreateEngine( &engineObject, 0, nullptr, 0, nullptr, nullptr );

初始化/销毁:

(*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);

(*engineObject)->Destroy(engineObject);

获取管理接口:

SLEngineItf engineEngine;

(*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &(engineEngine));

下面我们就可以愉快地使用 engineEngine 来创建所有 OpenSL ES 的其他对象了。

4.2 Media Object

OpenSL ES 里面另一组比较重要的对象就是 Media Object ,代表着多媒体功能的抽象,比如:player、recorder 等等。

我们可以通过 SLEngineItf 提供的 CreateAudioPlayer 方法来创建一个 player 对象实例,可以通过 SLEngineItf 提供的 CreateAudioRecorder 方法来创建一个 recorder 实例。

4.3 Data Source 和 Data Sink

OpenSL ES 里面,这两个结构体均是作为创建 Media Object 对象时的参数而存在的,data source 代表着输入源的信息,即数据从哪儿来、输入的数据参数是怎样的;而 data sink 则代表着输出的信息,即数据输出到哪儿、以什么样的参数来输出。

4.3.1 基本定义

Data Source 的定义如下:

typedef struct SLDataSource_ {

void *pLocator;

void *pFormat;

} SLDataSource;

Data Sink 的定义如下:

typedef struct SLDataSink_ {

void *pLocator;

void *pFormat;

} SLDataSink;

其中,pLocator 主要有如下几种:

SLDataLocator_Address

SLDataLocator_BufferQueue

SLDataLocator_IODevice

SLDataLocator_MIDIBufferQueue

SLDataLocator_URI

也就是说,Media Object 对象的输入源/输出源,既可以是 URL,也可以 Device,或者来自于缓冲区队列等等,完全是由 Media Object 对象的具体类型和应用场景来配置。

4.3.2 示例说明

不同的 Media Object 对象实例,data source 和 data sink 的具体内容是不一样的。

例如,对于 player 而言:

而对于 recorder 而言:

5. 示例程序及参考资料

限于篇幅,关于 OpenSL ES 的 Player 和 Recorder 相关 API 详细的用法,就不在本文展开了,其实理解了上面介绍了这些概念之后,结合官方的 《OpenSL_ES_Specification_1.0.1.pdf》,以及我给出的示例代码,很容易就能读懂和掌握这些 API 的用法了,示例代码地址如下:

6. 小结

关于如何 Android OpenSL ES API 就介绍到这儿了,文章中有不清楚的地方欢迎留言或者来信 lujun.hust@gmail.com 交流,或者关注我的新浪微博 @卢_俊 或者 微信公众号 @Jhuster 获取最新的文章和资讯。

Android中opensl架构图,Android音频开发(7):使用 OpenSL ES API(下)相关推荐

  1. android中使用tmf框架插件化开发的问题

    android中使用tmf框架插件化开发的问题 最近项目开发使用的是tmf框架,其中大多数都是通过源生和H5交互的方式来实现的,大体实现和别的三方框架是一样的,需要按照tmf的官方文档引入一些lib和 ...

  2. Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器

    Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器实例的示例: public class AudioPlayer implements MediaPlayer.OnPre ...

  3. 【Android FFMPEG 开发】Android 中使用 FFMPEG 将 PCM 音频采样转为 MP3 格式

    文章目录 一.前置操作 ( 移植 FFMPEG ) 二.FFMPEG 将 PCM 采样转为 MP3 格式的命令 三.Android FFMPEG 混音源代码完整示例 四.博客源码 一.前置操作 ( 移 ...

  4. android中帧布局效果,Android开发实现布局帧布局霓虹灯效果示例

    本文实例讲述了android开发实现布局帧布局霓虹灯效果.分享给大家供大家参考,具体如下: 效果图: 实现方式: framelayout中,设置8个textview,在主函数中,设计颜色数组,通过有序 ...

  5. android中checkbox使用方法,Android开发中CheckBox的简单用法示例

    本文实例讲述了Android开发中CheckBox的简单用法.分享给大家供大家参考,具体如下: CheckBox是一种在界面开发中比较常见的控件,Android中UI开发也有CheckBox,简单的说 ...

  6. android中edittext设置密码格式,Android 自定义EditText(带清理、密码可见、不可见)...

    实际开发中经常会遇到输入框,各种不同的需求,在一般情况下,清除内容,以及密码可见与不可见基本很常见,那么不废话直接上代码! 在res\values\attrs.xml中 .java import an ...

  7. 【译】Android中的安全数据— Android中的加密(第1部分)

    目录 Java密码体系结构 Android Key Store 样例项目 下一步是什么 安全提示 Java密码体系结构 Android建立在Java密码体系结构(JCA)的基础上,该体系结构提供了用于 ...

  8. android中的shape资源,Android Drawable资源讲解之shape篇

    运用好Android的drawable资源,在开发中就可以减少图片的使用量,这样既缩小了app的体积,也省去了设计图片的时间,而且也容易适配不同的屏幕尺寸. 今天首先来讲讲shape资源的使用. 1. ...

  9. android中服务播放音乐,android中用Service播放音乐

    一般的Android应用程序的音乐可以分为背景音乐和点击各种控件时的音效,前者一般为比较大的音乐文件,后者一般为比较小的音乐.在Android中一般用MediaPlayer类处理比较大的音频文件,用S ...

最新文章

  1. 5月“.公司”域名注册总量TOP15:西部数码第四
  2. 清华大学计算机系教授:马少平——计算机是如何实现智能的(附直播回放)...
  3. 上班族漫画(转收藏)
  4. python第一周小测验_荐测验1: Python基本语法元素 (第1周)
  5. 《中国管理安全服务(MSS)市场研究报告2010》读后感
  6. Linux常用的25条命令
  7. 基于iSroll 5.0实现的上拉加载和下拉刷新插件
  8. linux修改文件内容_详解5种实用方法---Linux系统清空或删除大文件内容
  9. goahead上传文件【原创】
  10. I.MX6 make menuconfig OTG to slave only mode
  11. Linux 命令速查
  12. c语言为什么运行慢,【图片】今天写几个性能测试,为什么C语言跑得这么慢呢??【c语言吧】_百度贴吧...
  13. 短视频秒播优化实践(一)
  14. 用remastersys备份LINUX,注意备份盘的空间占用
  15. 汉字区位码---非常浅显的知识点
  16. 2022全球C++及系统软件技术大会将于9月上海隆重召开,豪华嘉宾阵容揭晓
  17. 个人信息安全规范----7、个人信息安全事件处置
  18. 信号复数及希尔伯特变换的理解
  19. 测试经理必知必会-Kanban和Scrum区别
  20. 単語境界/非単語境界(¥b, ¥B)

热门文章

  1. Java——从键盘输入数组
  2. iOS定位库-INTULocationRequest
  3. 对待批评的的不同态度
  4. 两种PDF页面大小不一致的调整办法
  5. ajax请求封装,封装的ajax请求
  6. C语言编程的书写规则,关于C语言编程书写规范的规则和建议.doc
  7. tomcat介绍与使用
  8. 拍森 | numpy库
  9. 数据对齐-编辑距离算法详解(Levenshtein distance)
  10. 将兴趣变现,你会选择什么Dao社区?