1 Star 1 Fork 0

jackzhous / OpenSL ES

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

OpenSL ES音频库学习

简介

什么是OpenSL ES? openSL ES是一个专用于嵌入式系统的音频库,可以提供对音频的播放和录制等相关功能,在Android上Aduio Recoder都是基于此库实现的,同时,我们也可以在Android的JNI里面使用此库进行音频开发,官方介绍请点击

使用方式

OpenSL ES几乎都是通过一个Object一个Interface成对来获取一项功能,比如OpenSL ES的全局引擎engineObject和engineInterface:

	SLObjectItf engineObject;           //引擎始祖对象
    SLEngineItf engineInterface;        //引擎接口
	slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineInterface);

内部大致原理

内部状态机制

从上一步得知所有的功能都是先创建Object,在获取其interface,其内部大致有这么一个状态机制

  1. 创建Object时,其处于未实现UNREALIZED 状态,内部也没有为其分配任何资源
  2. Realize激活后,才能通过Object获取其功能Interface,此时处于REALIZED状态
  3. 当音频被抢占或出现错误,Object处于SUSPENDED暂停状态,如果想恢复REALIZED需要调用Object的Resume方法
  4. 当我们把Object销毁后,就进入UNREALIZED状态了,重新使用需要在REALIZED才行 下图是参考网图: 状态机制

IO回调机制

使用OpenSL ES进行音频录制和播放时,我们都是和一个缓冲区(自己创建)打交道,录音时,触发回调函数后,说明缓存区数据填满了,我们可以从里面取出录好的数据;播放时,触发回调函数后,说明缓冲区数据播完了,我们往缓冲区添加音频数据

部分功能介绍

录音Recorder

录音重点主要集中在初始化配置方面:

  • 配置输入和输出
  • 配置缓冲区IO回调
  • 创建RecorderObject和RecorderInterface

输入和输出

SLDataSource和SLDataSink

typedef struct SLDataSource_ {
	void *pLocator;			//输入数据类别
	void *pFormat;			//输入数据格式
} SLDataSource;

typedef struct SLDataSink_ {
	void *pLocator;
	void *pFormat;
} SLDataSink;

其中pLocator的类型可以是:

SLDataLocator_Address
SLDataLocator_BufferQueue
SLDataLocator_IODevice
SLDataLocator_MIDIBufferQueue
SLDataLocator_URI

针对录音的数据来源我们可以选择IODevice,以下是对IODevice的配置:

//录音源source
slHelper->ioDevice.locatorType = SL_DATALOCATOR_IODEVICE;       //源头是io设备
slHelper->ioDevice.deviceType = SL_IODEVICE_AUDIOINPUT;         //音频输入
slHelper->ioDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
slHelper->ioDevice.device = NULL;           //device ID生效的前提必须device NULL

配置录音的输出,我们选择SLDataLocator_BufferQueue类型,输出到缓冲区,还需要配置输出的数据给format

//输出
queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;  //输出到缓冲队列
queue.numBuffers = 2;     //2个缓冲队列

pcmFormat.formatType = SL_DATAFORMAT_PCM;     //录音数据格式
pcmFormat.numChannels = channels;
pcmFormat.samplesPerSec = sampleRate;
pcmFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;        //每个采样点bit
pcmFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
pcmFormat.channelMask = getChannelMask(channels);             //根据声道数确定掩码
pcmFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;             //字节小端模式

sink.pLocator = &(queue);
sink.pFormat = &(pcmFormat);

最后,就可以创建Recoder开始播放了:

///Recorder/////
SLInterfaceID id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
SLboolean required[] = {SL_BOOLEAN_TRUE};

(*engineInterface)->CreateAudioRecorder(engineInterface, &recorderObject
                          , &source, &sink, 1, id, required);
(*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);

//Register
(*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
                              &(androidBufferQueueItf));

(*androidBufferQueueItf)->RegisterCallback(androidBufferQueueItf, openSLCallBack, NULL);

//start recorder
(*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderInterface);
(*recorderInterface)->SetRecordState(recorderInterface, SL_RECORDSTATE_RECORDING);

ok,以上就是楼主学习过程中的一点小小心得,如有不正,请指正; 以下是我的学习demo

参考的链接: https://juejin.im/post/5bda5ed85188257f3e09d6f5 https://zhuanlan.zhihu.com/p/20865418

空文件

简介

Android移动端使用OpenSL ES 展开 收起
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/jackzhous/OpenSL-ES.git
git@gitee.com:jackzhous/OpenSL-ES.git
jackzhous
OpenSL-ES
OpenSL ES
master

搜索帮助