前言
网上关于 OpenSL ES 的资料相当少,最好的学习办法似乎是抄写 googlesamples/android-ndk 里的代码示例。这里打算使用 OpenSL ES 实现三个功能:
1) 播放 MP3 文件
2) 播放 PCM 文件
3) 录制 PCM 文件
其中第 2 个功能和第 1 个雷同,这篇博客里不会给出代码示例,需要的可以看 GitHub。
备注:CSDN 的样式太难看了,需要的可以到简书阅读本文:https://www.jianshu.com/p/5513a181580f
OpenSL ES 概述
OpenSL ES(Open Sound Library for Embedded Systems),是一种针对嵌入式系统特别优化过的硬件音频加速 API,免费并且可以跨平台使用。OpenSL ES 使用缓冲区队列机制,可以提供比系统 API 更高的性能。
在 OpenSL ES 中,所有的操作都是通过接口来完成的,尽管它使用了 C 语言来编写,但它的接口采用的是面向对象的,重要的几个接口是:
1) SLObjectItf :对象接口
2) SLEngineItf :引擎接口
3) SLPlayItf:播放接口
4) SLRecordItf:录制接口
5) SLBufferQueueItf :缓冲队列接口
其中:
1) Engine 是程序的入口,用于创建各种 Object
2) 一个 Object 对应一个或多个 Interface,Object 提供 Realize、Deatory、GetInterface 等基本接口
3) 实际的功能由各个 Interface 完成,比如播放音频,实际上是通过 SLPlayItf 来完成的
OpenSL ES 在不同系统上有不同的实现,有些接口在一些平台上可能无法使用,比如 Android 平台可以参考官方文档:面向 Android 的 OpenSL ES 来查看 Android 支持/不支持哪些功能。
以播放音频为例,最简单的代码编写流程为:
1) Engine::CreateAudioPlayer
2) Object::Realize
3) Object::GetInterface
4) Play::SetPlayState
其中,Object 可能的状态有:
/* Object state definitions */
#define SL_OBJECT_STATE_UNREALIZED ((SLuint32) 0x00000001)
#define SL_OBJECT_STATE_REALIZED ((SLuint32) 0x00000002)
#define SL_OBJECT_STATE_SUSPENDED ((SLuint32) 0x00000003)
使用 Engine 创建了一个 Object 时,它的状态是 UNREALIZED,必须使用方法 Realize 完成初始化,进入 REALIZED 状态,才可以进行下一步操作。如果出现错误或其它问题,它就会进入 SUSPENDED 状态,需要使用 Resume 方法才可以回到 REALIZED 状态。
播放 MP3 文件
这里以播放 Android 平台上的 asset 文件为例。
上面说过,Engine 是程序的入口,因此第一件事是创建 SLEngineItf:
void createEngine() {
SLresult result;
result = slCreateEngine(&engineObj, 0, nullptr, 0, nullptr, nullptr);
assert(result == SL_RESULT_SUCCESS);
(void) result;
result = (*engineObj)->Realize(engineObj, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
(void) result;
result = (*engineObj)->GetInterface(engineObj, SL_IID_ENGINE, &engine);
assert(SL_RESULT_SUCCESS == result);
(void) result;
const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
const SLboolean req[1] = {SL_BOOLEAN_FALSE};
(*engine)->CreateOutputMix(engine, &outputMixObj, 1, ids, req); // outputMixObj 用于输出声音数据
result =