简单OpenSL ES学习

初识OpenSL ES

  • OpenSL ES
    • Objects和Interfaces
  • 所有的Object在OpenSl里面我们拿到的都是一个SLObjectItf:
    • 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的说法其实我们根本不需要去管,一层嵌着一层,能大体知道它的设计思路即可,免得被它的对象和接口搞得自己混乱了。

其它更具体的代码这里就不再细讲了,网上的各种代码例子非常多,这里其实是为了加深我自己学习过程中的疑惑问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/97613.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[补题记录] Atcoder Beginner Contest 297(F)

URL:https://atcoder.jp/contests/abc297 目录 F Problem/题意 Thought/思路 Code/代码 F Problem/题意 给一个 H * W 的矩形,在其中任意放置 K 个点,由这 K 个点构成的最小矩形带来的贡献为该矩形的面积,这 K 个点构成一种…

1.6 IntelliJ IDEA开发工具

前言: ### 1.6 IntelliJ IDEA开发工具笔记 - **背景**: - 使用基础文本编辑器如记事本编写Java代码虽然可行,但存在效率低下且难以调试的问题。 - 集成开发环境 (IDE) 可以有效地提高Java程序的开发效率。 - **常见Java IDE**&#xf…

光伏发电预测(GRU模型,Python代码)

运行效果:光伏发电预测(GRU模型,Python代码)_哔哩哔哩_bilibili 所有库的版本: 1.数据集(连续10年不间断采集三个光伏电站的发电量及天气情况,每隔半个小时采集一次信息,因此&…

NICE-SLAM——论文简析

NICE-SLAM: Neural Implicit Scalable Encoding 现有的神经隐式表征方法会产生过度平滑的场景重建,并且难以扩展到大型场景。这些局限性主要是由于其简单的全连接网络架构没有将局部信息纳入观测。NICE-SLAM通过引入分层场景表示法,纳入了多层次的局部信…

uniapp实现上传文件功能

UniApp是一款跨平台的开发框架,可用于开发微信小程序、H5、Android和iOS等多种平台应用。实现上传文件功能需要以下步骤: 引入uni.uploadFile API,代码如下: uni.uploadFile({url: your upload url,filePath: your file path,na…

【Kotlin精简】第2章 集合

1 简介 在 Kotlin 中集合主要分为可变集合与只读集合,其中可变集合使用 “Mutable” 前缀 集合类名表示,比如 MutableList、MutableSet、MutableMap 等。而对于只读集合就是和 Java 中集合类名是一致。 Java 中的 List 非 Kotlin 中的 List , 因为 Kot…

GPT系列论文解读:GPT-3

GPT系列 GPT(Generative Pre-trained Transformer)是一系列基于Transformer架构的预训练语言模型,由OpenAI开发。以下是GPT系列的主要模型: GPT:GPT-1是于2018年发布的第一个版本,它使用了12个Transformer…

队列--二叉树层序遍历

/*1/ \2 3/\ /\4 5 6 7利用LinkedListQueue1. 头 [1] 尾12.头 [2 3] 尾1 23.头 [3 4 5] 尾1 24.头 [4 5 6 7] 尾1 2 35.头 [] 尾1 2 3 4 5 6 7*/ 代码&#xff1a; class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List&l…

ChatGPT Vision初体验

本周&#xff0c;OpenAI为其广受欢迎的 ChatGPT 平台发布了一项突破性的补充。除了处理文本之外&#xff0c;ChatGPT 现在还可以处理图像并聊天。 很难夸大这件事的重要性。目前多达70% 的内容是视觉内容而不是书面内容。人们每年会生成数千张照片&#xff0c;而当今许多最大的…

了解区块链技术和智能合约开发

了解区块链技术和智能合约开发 区块链技术和智能合约开发是当前科技领域的两大热门话题。它们不仅在金融领域有着广泛的应用&#xff0c;还在供应链管理、医疗保健、投票系统等众多领域崭露头角。本文将带您深入了解区块链技术和智能合约开发的基本概念以及如何开始自己的区块…

若依前端-应用路径发布和使用

官网的路径&#xff1a;前端手册 | RuoYi 应用路径 有些特殊情况需要部署到子路径下&#xff0c;例如&#xff1a;https://www.ruoyi.vip/admin&#xff0c;可以按照下面流程修改。 1、修改vue.config.js中的publicPath属性 publicPath: process.env.NODE_ENV "produ…

VR模拟鸡胚培养接种实验,打造沉浸式的学习环境

在医学教育领域&#xff0c;传统的鸡胚接种实验一直是教学的重要组成部分。然而&#xff0c;这种实验方法存在一定的局限性&#xff0c;如操作难度大、成本高、安全隐患等。为了解决这些问题&#xff0c;越来越多的教育机构开始尝试引入虚拟现实(VR)技术&#xff0c;以模拟鸡胚…

研发质量管理体系

研发质量管理体系的脉络是怎样的&#xff1f;如何建立适合组织发展的研发质量管理体系&#xff1f;质量管理的核心是什么&#xff1f;一些思考&#xff0c;一些线索&#xff0c;欢迎朋友们一起探讨、碰撞。

vscode 乱码解决

windows 10 系统 vs code 编译运行和调试 C/C_vscode windows编译_雪的期许的博客-CSDN博客 VS Code默认文件编码时UTF-8&#xff0c;这对大多数情况是没有问题的&#xff0c;却偏偏对C/C有问题。如果以UTF-8编码保存C/C代码&#xff0c;那么只能输出英文&#xff0c;另外使用…

我在 NPM 发布了新包: con-colors

链接地址&#xff1a;npmjs.com con-colors 安装依赖 yarn add con-colors使用 导入&#xff1a; import { print } from "con-colors";使用&#xff1a; print.succ("成功的消息"); print.err("失败的消息")例子&#xff1a; import { p…

红包雨高并发压测记录(200台机器压测实录)

压测5000线程10秒内循环5次&#xff0c;5台2核心4线程的机器&#xff0c;QPS2500 压测10000线程10秒内循环5次&#xff0c;10台2核心4线程的机器&#xff0c;QPS5000 压测200000线程10秒内循环5次&#xff0c;200台2核心4线程的机器&#xff0c;QPS100000 虽然接口异常率都为零…

【云计算网络安全】DDoS 缓解解析:DDoS 攻击缓解策略、选择最佳提供商和关键考虑因素

文章目录 一、前言二、什么是 DDoS 缓解三、DDoS 缓解阶段四、如何选择 DDoS 缓解提供商4.1 网络容量4.2 处理能力4.3 可扩展性4.4 灵活性4.5 可靠性4.6 其他考虑因素4.6.1 定价4.6.2 所专注的方向 文末送书《数据要素安全流通》本书编撰背景本书亮点本书主要内容 一、前言 云…

AI工程化—— 如何让AI在企业多快好省的落地?

作为计算机科学的一个重要领域&#xff0c;机器学习也是目前人工智能领域非常活跃的分支之一。机器学习通过分析海量数据、总结规律&#xff0c;帮助人们解决众多实际问题。随着机器学习技术的发展&#xff0c;越来越多的企业将机器学习技术作为核心竞争力&#xff0c;并运用在…

如何用万界星空科技低代码平台快速开发一个MES系统?

一、制造业工厂生产现状&#xff1a; 1、生产计划复杂 生产效率低&#xff0c;工作量大&#xff0c;周期长&#xff1b;生产计划执行准确性不高&#xff0c; 生产工单准时完工率过低&#xff1b;计划人员很难得到实际生产进度的准确信息&#xff1b;人员沟通成本高&#xff1…

端口没有占用,Springboot却提示端口占用了

1.问题描述 *************************** APPLICATION FAILED TO START ***************************Description:Web server failed to start. Port 19004 was already in use.Action:Identify and stop the process thats listening on port 19004 or configure this applica…