南京手机网站建设,淄博网站建设小程序,校园网站建设多少钱,凡客诚品网址是多少初识OpenSL ES OpenSL ESObjects和Interfaces 所有的Object在OpenSl里面我们拿到的都是一个SLObjectItf#xff1a;SLObjectItf_创建引擎创建过程要设计得这么麻烦#xff1f;#xff08;object的生命周期#xff09;这么多参数#xff0c;参数类型这么多学习障碍太大SLObjectItf_创建引擎创建过程要设计得这么麻烦object的生命周期这么多参数参数类型这么多学习障碍太大 创建混音器 OpenSL ES
简单来说OpenSL ES是一个嵌入式跨平台免费的音频处理库。 所以它不是Android特有的。它从PC端的整出来一个小一些的第三方库专门来给移动端使用跨平台、无授权费针对嵌入式系统精心优化的硬件音频加速 API。
最后一句话就是我们商业应用用的就是它所以要学习了解它。
据说人家是C语音兼容C然后以面对对象的思想设计的。
可以播放PCM的一个库。
Objects和Interfaces
我们要想使用一个对象必须创建这个对象然后通过这个对象拿到它提供的接口最后再通过接口提供的函数去执行。
设计的所有最顶层Object是音频引擎之后其它所有的对象都需要音频引擎这个对象传入。
它的Objects是有生命周期概念的。 Objects ⼀般有三种状态分别是UNREALIZED 不可⽤REALIZED可⽤SUSPENDED 挂起。
所有的Object在OpenSl里面我们拿到的都是一个SLObjectItf
SLObjectItf_
//调用全局方法创建一个引擎对象OpenSL ES唯一入口 SLresult result;result slCreateEngine(engineObject, 0, 0, 0, 0, 0);我们从官方文档里面看到了其它都是传入对象只有第一个engineObject是丢进去赋值的这也是C语音赋值正常流程。 这个engineObject的类型就是SLObjectItf我们看看这个engineObject是什么东西。
SL_API SLresult SLAPIENTRY slCreateEngine(SLObjectItf *pEngine,SLuint32 numOptions,const SLEngineOption *pEngineOptions,SLuint32 numInterfaces,const SLInterfaceID *pInterfaceIds,const SLboolean * pInterfaceRequired
) SL_API_DEPRECATED(30);这是函数定义具体实现在cpp文件那里我们看下这个SLObjectItf的定义
typedef const struct SLObjectItf_ * const * SLObjectItf;在C语言中typedef关键字可以用来为已存在的类型定义一个新的名称。这里typedef const struct SLObjectItf_ * const * SLObjectItf;是定义了一个新的类型名SLObjectItf这个新类型是const struct SLObjectItf_ *类型的别名。
这个语句可以分为两部分来解释
1、const struct SLObjectItf_ *这是一个指向const struct SLObjectItf_类型的指针。struct SLObjectItf_是一个结构体类型但是这里并没有给出这个结构体的具体定义所以无法知道它包含哪些字段和数据。const关键字表示这个指针自身是一个常量不能被修改但指针所指向的内容是可以被修改的。
2、* SLObjectItf这是一个指向上面定义的const struct SLObjectItf_ *类型的指针。也就是说SLObjectItf是一个指向指向const struct SLObjectItf_类型的指针的指针。这样的数据结构通常被用于实现动态链接库DLL或者共享库因为这样的设计可以让使用者在使用这些库的时候不直接操作原始的接口而是通过这个指针的指针来操作。
简单来说SLObjectItf是SLObjectItf_ 类型的别名当调用调用全局方法创建一个引擎对象唯一入口的时候就会根据传入的参数类型来给这个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);
};上面说的Objects和Interfaces的关系在这里就是SLObjectItf_ 是对象它定义了很多的函数实例化这个对象之后我们就可以 使用对象里面的函数里面定义了接口就是一个对象Interfaces
如果是java这种面对对象语音真正的接口的话必须实例化才行这里显然就是名义上的接口既然人家说是按照面对对象的思维来设计我们就按照这种思维来理解但是不能把它代入到具体的语音规则中。
创建引擎
这是在播放PCM数据的demo中的代码
/*********** 1 创建引擎 获取SLEngineItf***************/SLresult result;result slCreateEngine(engineObject, 0, 0, 0, 0, 0);if (result ! SL_RESULT_SUCCESS)return;result (*engineObject)-Realize(engineObject, SL_BOOLEAN_FALSE);if (result ! SL_RESULT_SUCCESS)return;result (*engineObject)-GetInterface(engineObject, SL_IID_ENGINE, engineEngine);if (result ! SL_RESULT_SUCCESS)return;if (engineEngine) {LOGD(get SLEngineItf success);} else {LOGE(get SLEngineItf failed);}/*********** 1 创建引擎 ***************/这是在录音demo中的代码 SLEngineOption pEngineOptions[] {(SLuint32) SL_ENGINEOPTION_THREADSAFE,(SLuint32) SL_BOOLEAN_TRUE};// 创建引擎对象,//调用全局方法创建一个引擎对象OpenSL ES唯一入口SLresult result;result slCreateEngine(engineObject, //对象地址用于传出对象1, // 可选配置数组的大小pEngineOptions, // 选配置数组的参数 录音时候一般会这么配置主要是为了兼容其它平台避免出现不兼容情况。0, //支持的接口数量nullptr, //具体的要支持的接口是枚举的数组nullptr//具体的要支持的接口是开放的还是关闭的也是一个数组这三个参数长度是一致的);assert(SL_RESULT_SUCCESS result);/* Realizing the SL Engine in synchronous mode. *///实例化这个对象result (*engineObject)-Realize(engineObject, SL_BOOLEAN_FALSE);assert(SL_RESULT_SUCCESS result);// get the engine interface, which is needed in order to create other objects//从这个对象里面获取引擎接口(*engineObject)-GetInterface(engineObject, SL_IID_ENGINE, engineEngine);assert(SL_RESULT_SUCCESS result);创建过程要设计得这么麻烦object的生命周期
OpenSL ES 的 Object 一般有三种状态分别是: UNREALIZED (不可用)REALIZED (可用)SUSPENDED(挂起) 。 obiect 外干UNREALIZED(不用)状态时系统不会为其分配资源: 调用 Realize 方法后便进入 REALIZED(可用)状态此时对象的各个功能和资源可以正常访问;当系统音频相关的硬件设备被其他进程占用时,OpenSL ES Obiect 便会进入 SUSPENDED (挂起) 状态随后调用 Resume 方法可使对象重回 REALIZED (可用)状态;当 0bject 使用结束后调用 Destroy 方法释放资源是对象重回 UNREALIZED (不可用)状态
因为设计到硬件所以它的使用有一个过程不像是存代码创建赋值直接在内存中生成某个对象。
这么多参数参数类型这么多学习障碍太大
android端在NDK中使用OpenSL ES的创建过程非常麻烦但实际上在开发过程这些代码是很固定的基本没人会手打都是复制张贴所以无需担心那么多。 比如创建混音器参数选项那么多实际上还真不太可能全研究透而是什么需求配置什么参数看具体场景需求之后再去查找其它方面的大体都是固定式代码所以有一定的了解即可。
创建混音器 /*********** 2 创建混音器 ***************/const SLInterfaceID mids[1] {SL_IID_ENVIRONMENTALREVERB};// 环境回响const SLboolean mreq[1] {SL_BOOLEAN_FALSE};result (*engineEngine)-CreateOutputMix(engineEngine, outputMixObject, 1, mids, mreq);if (result ! SL_RESULT_SUCCESS) {LOGE(CreateOutputMix failed);return;} else {LOGD(CreateOutputMix success);}//实例化混音器result (*outputMixObject)-Realize(outputMixObject, SL_BOOLEAN_FALSE);if (result ! SL_RESULT_SUCCESS) {LOGE(mixer init failed);} else {LOGD(mixer init success);}result (*outputMixObject)-GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,outputMixEnvironmentalReverb);if (SL_RESULT_SUCCESS result) {// 走廊效果SLEnvironmentalReverbSettings reverbSettings SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;result (*outputMixEnvironmentalReverb)-SetEnvironmentalReverbProperties(outputMixEnvironmentalReverb, reverbSettings);(void) result;}/*********** 2 创建混音器 ***************/可以看到在这里object是我们创建引擎拿到的interface对象通过它实例化我们的outputMixObject对象 object和interface的说法其实我们根本不需要去管一层嵌着一层能大体知道它的设计思路即可免得被它的对象和接口搞得自己混乱了。
其它更具体的代码这里就不再细讲了网上的各种代码例子非常多这里其实是为了加深我自己学习过程中的疑惑问题。