简介

82da5f87314f

NDK开发OpenSL ES跨平台高效音频解决方案.png

OpenSL ES全称为Open Sound Library for Embedded Systems,即嵌入式音频加速标准。OpenSL ES是无授权费、跨平台、针对嵌入式系统精心优化的硬件音频加速 API。它为嵌入式移动多媒体设备上的本地 应用程序开发者提供了标准化、高性能、低响应时间的音频功能实现方法,同时还实现了软/硬件音频性能的直接跨平台部署,不仅降低了执行难度,而且促进了高级音频市场的发展。

OpenSL ES里面有对象和接口的概念:

对象:类似于C++中类用来提供一组资源及其状态的抽象,也就是我们可以根据特定类型type来获取一个音频录制的对象,但是对于这个对象我们并不能直接操作。

接口:接口是对象提供一组特定功能方法的抽象,也就是可以从对象中获取接口,然后通过接口来改变对象的状态以便使用对象的功能。

使用:

1.导入OpenSL ES库

因为opensl是内嵌在android系统里的,所以我们需要连接到我们工程使用

#找打Android lib库里面的libOpenSLES.so的库

find_library( OpenSLES-lib

OpenSLES )

#链接到你的native工程的库

target_link_libraries( your-native.so

${OpenSLES-lib}

)

然后引入头文件

#include

#include

2.创建OpenSL ES引擎并初始化

SLObjectItf engineObject; //引擎对象

SLEngineItf engineInterface; //引擎接口

SLObjectItf outputMixObject; //混音器

SLObjectItf audioPlayerObject; //播放器对象

SLAndroidSimpleBufferQueueItf andioPlayerBufferQueueItf; //缓冲器队列接口

SLPlayItf audioPlayInterface; //播放接口

SLEngineOption options[] = {

{(SLuint32)SL_ENGINEOPTION_THREADSAFE, (SLuint32)SL_BOOLEAN_TRUE}

};

slCreateEngine(&engineObject,ARRAY_LEN(engineObject),options,0,0,0); //没有接口

//实例化对象

//象创建之后,处于未实例化状态,对象虽然存在但未分配任何资源,使用前先实例化(使用完之后destroy)

RealizeObject(engineObject);

关于slCreateEngine()这个全局方法:

SL_API SLresult SLAPIENTRY slCreateEngine(

SLObjectItf *pEngine, //对象地址,用于传出对象

SLuint32 numOptions, //配置参数数量

const SLEngineOption *pEngineOptions, //配置参数,为枚举数组

SLuint32 numInterfaces, //支持的接口数量

const SLInterfaceID *pInterfaceIds, //具体的要支持的接口,是枚举的数组

const SLboolean *pInterfaceRequired //具体的要支持的接口是开放的还是关闭的,也是一个数组,这三个参数长度是一致的

);

3.获取引擎接口

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

4.实例化混音器

//4.创建输出混音器

(*engineInterface)->CreateOutputMix(engineInterface,&outputMixObject,0,0,0); //没有接口

//实例化混音器

RealizeObject(outputMixObject);

5.创建音频播放对象

// Android针对数据源的简单缓冲区队列定位器

SLDataLocator_AndroidSimpleBufferQueue dataSourceLocator = {

SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // 定位器类型

1 // 缓冲区数

};

// PCM数据源格式

SLDataFormat_PCM dataSourceFormat = {

SL_DATAFORMAT_PCM, // 格式类型

wav_get_channels(wav), // 通道数

wav_get_rate(wav) * 1000, // 毫赫兹/秒的样本数

wav_get_bits(wav), // 每个样本的位数

wav_get_bits(wav), // 容器大小

SL_SPEAKER_FRONT_CENTER, // 通道屏蔽

SL_BYTEORDER_LITTLEENDIAN // 字节顺序

};

// 数据源是含有PCM格式的简单缓冲区队列

SLDataSource dataSource = {

&dataSourceLocator, // 数据定位器

&dataSourceFormat // 数据格式

};

// 针对数据接收器的输出混合定位器

SLDataLocator_OutputMix dataSinkLocator = {

SL_DATALOCATOR_OUTPUTMIX, // 定位器类型

outputMixObject // 输出混合

};

// 数据定位器是一个输出混合

SLDataSink dataSink = {

&dataSinkLocator, // 定位器

0 // 格式

};

// 需要的接口

SLInterfaceID interfaceIds[] = {

SL_IID_BUFFERQUEUE

};

// 需要的接口,如果所需要的接口不要用,请求将失败

SLboolean requiredInterfaces[] = {

SL_BOOLEAN_TRUE // for SL_IID_BUFFERQUEUE

};

(*engineInterface)->CreateAudioPlayer(

engineInterface,

&audioPlayerObject,

&dataSource,

&dataSink,

ARRAY_LEN(interfaceIds),

interfaceIds,

requiredInterfaces);

//实例化音频播放器

RealizeObject(audioPlayerObject);

6.获得缓冲区队列接口Buffer Queue Interface

//通过缓冲区队列接口对缓冲区进行排序播放

(*audioPlayerObject)->GetInterface(audioPlayerObject,SL_IID_BUFFERQUEUE,&andioPlayerBufferQueueItf);

7.注册音频播放器回调函数

当播放器完成对前一个缓冲区队列的播放时,回调函数会被调用,然后我们又继续读取音频数据,直到结束

//缓冲区的大小

bufferSize = wav_get_channels(wav) * wav_get_rate(wav) * wav_get_bits(wav);

buffer = new unsigned char[bufferSize];

PlayerContext *ctx = new PlayerContext(wav,buffer,bufferSize);

(*andioPlayerBufferQueueItf)->RegisterCallback(andioPlayerBufferQueueItf,PlayerCallBack,ctx);

RegisterCallback函数的原型:

SLresult (*RegisterCallback) (

SLAndroidSimpleBufferQueueItf self,

slAndroidSimpleBufferQueueCallback callback,

void* pContext

);

第一个参数是SLAndroidSimpleBufferQueueItf对象,第二个参数是回调函数,第三个参数是一个void,第三个参数一般指向一个封装的类或者结构体,保存一些回调函数中可能用到的信息,回调函数的规范是必须有两个参数,且第一个参数SLAndroidSimpleBufferQueueItf类型,第二个参数是void,指向封装的结构体

PlayerContext:

struct PlayerContext{

WAV wav;

unsigned char *buffer;

size_t bufferSize;

PlayerContext(WAV wav,

unsigned char *buffer,

size_t bufferSize){

this->wav = wav;

this->buffer = buffer;

this->bufferSize = bufferSize;

}

};

PlayerCallBack:

void PlayerCallBack(SLAndroidSimpleBufferQueueItf andioPlayerBufferQueue,void *context){

PlayerContext* ctx = (PlayerContext*)context;

//读取数据

ssize_t readSize = wav_read_data(ctx->wav,ctx->buffer,ctx->bufferSize);

if(0 < readSize){

(*andioPlayerBufferQueue)->Enqueue(andioPlayerBufferQueue,ctx->buffer,readSize);

}else{

//destroy context

CloseWaveFile(ctx->wav); //关闭文件

delete ctx->buffer; //释放缓存

}

}

8.获取Play Interface

通过对SetPlayState函数来启动播放音乐,一旦播放器被设置为播放状态,该音频播放器开始等待缓冲区排队就绪

(*audioPlayerObject)->GetInterface(audioPlayerObject,SL_IID_PLAY,&audioPlayInterface);

//设置播放状态

(*audioPlayInterface)->SetPlayState(audioPlayInterface,SL_PLAYSTATE_PLAYING);

9.开始

第一个缓冲区入队

PlayerCallBack(andioPlayerBufferQueueItf,ctx);

Android中opensl架构,Android OpenSL ES详解相关推荐

  1. android中怎么网络判断,Android中判断网络是否连接实例详解

    Android中判断网络是否连接实例详解 在android中,如何监测网络的状态呢,这个有的时候也是十分重要的,方法如下: public class ConnectionDetector { priv ...

  2. android sqlite自定义函数,Android中自定义一个View的方法详解

    本文实例讲述了Android中自定义一个View的方法.分享给大家供大家参考,具体如下: Android中自定义View的实现比较简单,无非就是继承父类,然后重载方法,即便如此,在实际编码中难免会遇到 ...

  3. android progressbar icon,android中ProgressDialog与ProgressBar的使用详解

    一 .ProgressDialogProgressDialog与ProgressBar在UI中动态显示一个加载图标显示程序运行状态.ProgressDialog是继承自Android.app.Prog ...

  4. Android中attrs.xml文件的使用详解

    $*********************************************************************************************$ 博主推荐 ...

  5. android中的mvp模式怎么定义,详解MVP模式在Android开发中的应用

    一.MVP介绍 随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Mode ...

  6. android编程xml动画,Android中xml设置Animation动画效果详解

    在Android中,Animation动画效果的实现可以通过两种方式进行实现,一种是tweened animation渐变动画,另一种是frame by frame animation画面转换动画. ...

  7. android 图库开发实例,Android中从图库中选取图片实例详解

    android 从图库中选取图片 在android中,如何从图库gallary中挑选图片呢,其实很简单,步骤如下 1) 设计一个imageview,用来显示图库选出来的图片 android:orien ...

  8. android中edittext属性,Android中EditText的inputType属性的详解

    xml的inputtype的值. Android:inputType="none" android:inputType="text" android:input ...

  9. Android中ExpandableListView控件的用法详解

    <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widge ...

  10. Android中设置定时闹钟以及AlarmManager详解

    AlarmManager是提供一种访问系统闹钟服务的方式,允许你去设置在将来的某个时间点去执行你的应用程序.当你的闹钟响起(时间到)时,在它上面注册的一个意图(Intent)将会被系统以广播发出,然后 ...

最新文章

  1. Cytoscape: MCODE增强包的网络模块化分析
  2. sqlrelay mysql_数据库连接池SQL Relay安装使用-Java架构师必看
  3. Weblogic12C 集群实现session同步
  4. PowerDesigner 教程篇 - 概念数据模型
  5. java 级联下拉列表_java 下拉框级联(年月日级联)
  6. Sedawk笔记之awk篇:快速了解Awk(三)
  7. SSIS 学习(2):数据流任务(上)
  8. 优秀自我简介200字_全球战疫 翰墨传情——东方盛世杯网络公益书画展优秀作品【二】...
  9. Mybatis中resultMap
  10. 关于插件管理器Alcatraz的一些问题
  11. 对于vue的评价:没事情做可以学
  12. 无限级分销系统数据库表设计
  13. 礼县职业中等专业学校计算机,礼县职业中等专业学校
  14. Java程序员在写SQL程序时候常犯的10个错误
  15. Ubuntu18.04 iso文件下载地址
  16. google vr 简介
  17. 据说教师资格证除了当老师还有这些用途
  18. 深圳哪个区最富,哪个区最穷?最新GDP排名出炉,没想到第二名是
  19. 医院预约挂号系统使用说明
  20. UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' in position 的解决方法

热门文章

  1. 文献集锦 | 非因空间多组学技术在胰腺癌肿瘤微环境中的研究策略
  2. 组合数学 - 全错位排序公式
  3. 10 个杀手级的自动化脚本
  4. 程序员这个职业赚钱吗?能赚多少钱?
  5. 30个深度学习库:按Python、C++、Java、JavaScript、R等10种语言分类
  6. Ubuntu20.04添加用户到root组方法
  7. 数字滤波--递推平均滤波
  8. Swagger UI
  9. brew 安装pip_在MacOs安装pip 及各种问题解决
  10. 2021-04-10 粤嵌单片机兴趣课(二)