Android中opensl架构,Android OpenSL ES详解
简介
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详解相关推荐
- android中怎么网络判断,Android中判断网络是否连接实例详解
Android中判断网络是否连接实例详解 在android中,如何监测网络的状态呢,这个有的时候也是十分重要的,方法如下: public class ConnectionDetector { priv ...
- android sqlite自定义函数,Android中自定义一个View的方法详解
本文实例讲述了Android中自定义一个View的方法.分享给大家供大家参考,具体如下: Android中自定义View的实现比较简单,无非就是继承父类,然后重载方法,即便如此,在实际编码中难免会遇到 ...
- android progressbar icon,android中ProgressDialog与ProgressBar的使用详解
一 .ProgressDialogProgressDialog与ProgressBar在UI中动态显示一个加载图标显示程序运行状态.ProgressDialog是继承自Android.app.Prog ...
- Android中attrs.xml文件的使用详解
$*********************************************************************************************$ 博主推荐 ...
- android中的mvp模式怎么定义,详解MVP模式在Android开发中的应用
一.MVP介绍 随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Mode ...
- android编程xml动画,Android中xml设置Animation动画效果详解
在Android中,Animation动画效果的实现可以通过两种方式进行实现,一种是tweened animation渐变动画,另一种是frame by frame animation画面转换动画. ...
- android 图库开发实例,Android中从图库中选取图片实例详解
android 从图库中选取图片 在android中,如何从图库gallary中挑选图片呢,其实很简单,步骤如下 1) 设计一个imageview,用来显示图库选出来的图片 android:orien ...
- android中edittext属性,Android中EditText的inputType属性的详解
xml的inputtype的值. Android:inputType="none" android:inputType="text" android:input ...
- Android中ExpandableListView控件的用法详解
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widge ...
- Android中设置定时闹钟以及AlarmManager详解
AlarmManager是提供一种访问系统闹钟服务的方式,允许你去设置在将来的某个时间点去执行你的应用程序.当你的闹钟响起(时间到)时,在它上面注册的一个意图(Intent)将会被系统以广播发出,然后 ...
最新文章
- Cytoscape: MCODE增强包的网络模块化分析
- sqlrelay mysql_数据库连接池SQL Relay安装使用-Java架构师必看
- Weblogic12C 集群实现session同步
- PowerDesigner 教程篇 - 概念数据模型
- java 级联下拉列表_java 下拉框级联(年月日级联)
- Sedawk笔记之awk篇:快速了解Awk(三)
- SSIS 学习(2):数据流任务(上)
- 优秀自我简介200字_全球战疫 翰墨传情——东方盛世杯网络公益书画展优秀作品【二】...
- Mybatis中resultMap
- 关于插件管理器Alcatraz的一些问题
- 对于vue的评价:没事情做可以学
- 无限级分销系统数据库表设计
- 礼县职业中等专业学校计算机,礼县职业中等专业学校
- Java程序员在写SQL程序时候常犯的10个错误
- Ubuntu18.04 iso文件下载地址
- google vr 简介
- 据说教师资格证除了当老师还有这些用途
- 深圳哪个区最富,哪个区最穷?最新GDP排名出炉,没想到第二名是
- 医院预约挂号系统使用说明
- UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' in position 的解决方法