接受 pcm 原始音频脉冲数据

# 简介

# Object SL 对象

代码中的 SLObjectItf 类型,
每个对象都有三种状态:

  • Unrelalized (initial state) : 不可用状态 , 对接是活跃的,但是还没有分配资源,处于不可用状态,对象内接口的方法不能使用。
  • Realized :可用状态。对象资源已分配,可以使用对象
  • Suspended (optional state): 挂起状态,所需资源比可用状态要少,但是在挂起期间保留了状态信息。当资源不足时,系统可以选择将对象状态改成挂起状态或是不可用状态

OpenSLES Object state diagram

# Interface 接口

由特定对象提供的相关特性集合的抽象,在代码中一般为 SLxxxxItf . 接口必须由特定对象进行生成。

# 一般使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//声明对象和接口
SLObjectItf object = nullptr;
SLxxxxItf itf = nullptr;
// init object创建对象
...
// 初始化对象,分配资源
(*object)->Realize(object,SL_BOOLEAN_FALSE);
//check result
...
// 初始化接口,第二个参数指定接口类型
(*object)->GetInterface(object,SL_IID_XXX,&itf);
...
//接口可以使用了

# 总结

可以理解为一个对象代表了一个资源和状态,它内部有一系列的接口,对象本身不提供操作,而是由对象内部的接口提供方法调用。

# OpenSLES 使用流程:

# 环境配置

Android 环境配置,在 CMakeLists 中将 OpenSLES 加入到目标库链接库列表中

1
2
3
4
5
6
7
8

CMakeLists.txt

target_link_libraries(nativelib

....
OpenSLES
${log-lib} )

需要在头文件中加上引用

1
2
3
4
5
opensles_player.h

#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

# 初始化

先看一个图
OpenSLES audio flow diagram

# 1. 初始化引擎

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
SLObjectItf m_engine_obj = nullptr;
SLEngineItf m_engine = nullptr;

bool OpenSLRender::CreateEngine() {
SLresult lresult =slCreateEngine(&m_engine_obj,0, nullptr,0, nullptr, nullptr);
if(CheckError(lresult, "Engine")) return false;
lresult = asInterface(m_engine_obj)->Realize(m_engine_obj,SL_BOOLEAN_FALSE);
if(CheckError(lresult,"EngineRealize")) return false;

lresult = asInterface(m_engine_obj)->GetInterface(m_engine_obj,SL_IID_ENGINE,&m_engine);
if(CheckError(lresult,"GetInterface")) return false;

return true;
}

# 2. 初始化合成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 合成器对象
SLObjectItf m_output_mix_obj = nullptr;
// 环境混响接口
SLEnvironmentalReverbItf m_output_mix_evn_reverb = nullptr;
// 环境混响设置参数
SLEnvironmentalReverbSettings m_output_mix_evn_settings = SL_I3DL2_ENVIRONMENT_PRESET_DEFAULT;


bool OpenSLRender::CreateOutputMixer() {
const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB};
const SLboolean mreq[1] = {SL_BOOLEAN_FALSE};

//使用Engine接口创建合成器对象
SLresult lresult = asInterface(m_engine)->CreateOutputMix(m_engine,&m_output_mix_obj,1,mids,mreq);

if(CheckError(lresult,"Output Mix")) return false;
//合成器对象初始化
lresult = asInterface(m_output_mix_obj)->Realize(m_output_mix_obj,SL_BOOLEAN_FALSE);
if(CheckError(lresult,"Mix Realize")) return false;
//使用合成器对象获取环境混响接口
lresult = asInterface(m_output_mix_obj)->GetInterface(m_output_mix_obj,SL_IID_ENVIRONMENTALREVERB,&m_output_mix_evn_reverb);
if(CheckError(lresult,"Mix Env Reverb")) return false;

//如果环境混响接口获取成功,设置环境混响属性为上面定义的默认值
if(lresult == SL_RESULT_SUCCESS){
(*m_output_mix_evn_reverb)->SetEnvironmentalReverbProperties(m_output_mix_evn_reverb,&m_output_mix_evn_settings);
}
return true;
}

# 3. 初始化并配置播放器对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//播放器对象
SLObjectItf m_pcm_player_obj = nullptr;
//播放器接口
SLPlayItf m_pcm_player = nullptr;
//音量接口
SLVolumeItf m_pcm_volume = nullptr;

// Android缓冲区队列接口
SLAndroidSimpleBufferQueueItf m_pcm_buffer = nullptr;


bool OpenSLRender::ConfigPlayer() {
SLDataLocator_AndroidSimpleBufferQueue android_queue ={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,SL_QUEUE_BUFFER_COUNT};
// 定义PCM数据格式
SLDataFormat_PCM pcm = {
SL_DATAFORMAT_PCM,
(SLuint32)2,
SL_SAMPLINGRATE_44_1,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN
};
SLDataSource slDataSource ={&android_queue,&pcm};
SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX,m_output_mix_obj};
SLDataSink dataSink = {&outputMix, nullptr};


SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE,SL_IID_EFFECTSEND,SL_IID_VOLUME};
SLboolean reqs[3] = {SL_BOOLEAN_TRUE,SL_BOOLEAN_TRUE,SL_BOOLEAN_TRUE,};

// 通过Engine接口创建音频播放器对象
SLresult lresult = asInterface(m_engine)->CreateAudioPlayer(m_engine,&m_pcm_player_obj,&slDataSource,&dataSink,3,ids,reqs);
if(CheckError(lresult,"Create Audio Player")) return false;
// 初始化音频播放器对象
lresult = asInterface(m_pcm_player_obj)->Realize(m_pcm_player_obj,SL_BOOLEAN_FALSE);
if(CheckError(lresult,"Player Realize")) return false;
// 使用音频播放器对象获取播放接口
lresult = asInterface(m_pcm_player_obj)->GetInterface(m_pcm_player_obj,SL_IID_PLAY,&m_pcm_player);
if(CheckError(lresult,"Player GetInterface")) return false;

// 使用音频播放器对象获取缓冲区队列接口
lresult = asInterface(m_pcm_player_obj)->GetInterface(m_pcm_player_obj,SL_IID_BUFFERQUEUE,&m_pcm_buffer);
if(CheckError(lresult,"Buffer GetInterface")) return false;

// 缓冲区队列注册缓冲区数据可用回调接口
lresult = (*m_pcm_buffer)->RegisterCallback(m_pcm_buffer,sReadPcmBufferCbFun,this);
if(CheckError(lresult,"Buffer RegisterCallback")) return false;

// 使用音频播放器对象获取音量接口
lresult = asInterface(m_pcm_player_obj)->GetInterface(m_pcm_player_obj,SL_IID_VOLUME,&m_pcm_volume);
if(CheckError(lresult,"Player Volume GetInterface")) return false;

LOGD(TAG,"OpenSL ES init success");
return true;
}

# 播放

创建一个播放线程,
解码器将解码数据 push 到 PCM 数据缓冲队列中,通知播放器线程启动播放

1
2
3
4
5
6
7
8
9
10
11

void createThread(){
...
std::thread t = std::thread(cb.render);
}



void cb(OpenSLRender *render){

}

Edited on Views times