1. 采用面向?qū)ο蟮?C 語言接口
??OpenSL ES 雖然是 C 語言編寫笛丙,但是它的接口采用的是面向?qū)ο蟮姆绞剑⒉皇翘峁┮幌盗械暮瘮?shù)接口价说,而是以 Interface 的方式來提供 API拯啦,這是理解 OpenSL ES API 的一個比較重要的點(diǎn)。
??例如熔任,實(shí)例化引擎的過程如下:
SLObjectItf slObjEngine = NULL;
SLresult result = (*slObjEngine)->Realize(slObjEngine, SL_BOOLEAN_FALSE);
??由于C語言不存在this指針褒链,所以參數(shù)中需要將對象本身傳入。
2. Objects 和 Interfaces
??OpenSL ES 有兩個必須理解的概念疑苔,就是Object 和 Interface甫匹,Object 可以想象成 Java 的 Object 類,Interface 可以想象成 Java 的 Interface惦费,但它們并不完全相同兵迅,下面進(jìn)一步解釋他們的關(guān)系:
??(1) 每個 Object 可能會存在一個或者多個 Interface,官方為每一種 Object 都定義了一系列的 Interface
??(2)每個 Object 對象都提供了一些最基礎(chǔ)的操作薪贫,比如:Realize恍箭,Resume,GetState瞧省,Destroy 等等扯夭,如果希望使用該對象支持的功能函數(shù)鳍贾,則必須通過其 GetInterface 函數(shù)拿到 Interface 接口,然后通過 Interface 來訪問功能函數(shù)
??(3)并不是每個系統(tǒng)上都實(shí)現(xiàn)了 OpenSL ES 為 Object 定義的所有 Interface交洗,所以在獲取 Interface 的時候需要做一些選擇和判斷
??如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 (*Destroy) (
SLObjectItf self
);
...
};
3. OpenSL ES 的狀態(tài)機(jī)制
??任何一個 OpenSL ES 的對象骑科,創(chuàng)建成功后,都進(jìn)入 SL_OBJECT_STATE_UNREALIZED 狀態(tài)构拳,這種狀態(tài)下咆爽,系統(tǒng)不會為它分配任何資源,直到調(diào)用 Realize 函數(shù)為止置森。
??Realize 后的對象斗埂,就會進(jìn)入 SL_OBJECT_STATE_REALIZED 狀態(tài),這是一種“可用”的狀態(tài)凫海,只有在這種狀態(tài)下呛凶,對象的各個功能和資源才能正常地訪問。
??當(dāng)一些系統(tǒng)事件發(fā)生后盐碱,比如出現(xiàn)錯誤或者 Audio 設(shè)備被其他應(yīng)用搶占,OpenSL ES 對象會進(jìn)入 SL_OBJECT_STATE_SUSPENDED 狀態(tài)沪伙,如果希望恢復(fù)正常使用瓮顽,需要調(diào)用 Resume 函數(shù)。
??當(dāng)調(diào)用對象的 Destroy 函數(shù)后围橡,則會釋放資源暖混,并回到 SL_OBJECT_STATE_UNREALIZED 狀態(tài)。
??簡言之翁授,一個 OpenSL ES 對象的生命周期拣播,就是從 create 到 destroy 的過程,生命周期的控制收擦,都是通過開發(fā)者顯示調(diào)用來完成的贮配。
4. 常用的對象和結(jié)構(gòu)體
??在 OpenSL ES 中,一切 API 的訪問和控制都是通過 Interface 來完成的塞赂。
4.1 Engine Object 和 SLEngineItf Interface
??(1)管理 Audio Engine 的生命周期
??(2)提供管理接口: SLEngineItf泪勒,該接口可以用來創(chuàng)建所有其他的 Object 對象
??(3)提供設(shè)備屬性查詢接口:SLEngineCapabilitiesItf 和 SLAudioIODeviceCapabilitiesItf,這些接口可以查詢設(shè)備的一些屬性信息
??Engine Object 對象的創(chuàng)建方法如下:
SLObjectItf engineObject;
slCreateEngine( &engineObject, 0, nullptr, 0, nullptr, nullptr );
??初始化/銷毀:
(*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
(*engineObject)->Destroy(engineObject);
??下面我們就可以愉快地使用 engineEngine 來創(chuàng)建所有 OpenSL ES 的其他對象了宴猾。
4.2 Media Object
??OpenSL ES 里面另一組比較重要的對象就是 Media Object 圆存,代表著多媒體功能的抽象,比如:player仇哆、recorder 等等沦辙。
??我們可以通過 SLEngineItf 提供的 CreateAudioPlayer 方法來創(chuàng)建一個 player 對象實(shí)例,可以通過 SLEngineItf 提供的 CreateAudioRecorder 方法來創(chuàng)建一個 recorder 實(shí)例讹剔。
4.3 SLDataSource 和 SLDataSink
??OpenSL ES 里面油讯,這兩個結(jié)構(gòu)體均是作為創(chuàng)建 Media Object 對象時的參數(shù)而存在的详民,
??SLDataSource 代表著輸入源的信息,即數(shù)據(jù)從哪兒來撞羽、輸入的數(shù)據(jù)參數(shù)是怎樣的阐斜;
??SLDataSink 則代表著輸出的信息,即數(shù)據(jù)輸出到哪兒诀紊、以什么樣的參數(shù)來輸出谒出。
??Data Source 的定義如下:
typedef struct SLDataSource_ {
void *pLocator;
void *pFormat;
} SLDataSource;
??Data Sink 的定義如下:
typedef struct SLDataSink_ {
void *pLocator;
void *pFormat;
} SLDataSink;
??其中,pLocator 主要有如下幾種:
SLDataLocator_Address
SLDataLocator_BufferQueue
SLDataLocator_IODevice
SLDataLocator_MIDIBufferQueue
SLDataLocator_URI
??也就是說邻奠,Media Object 對象的輸入源/輸出源笤喳,既可以是 URL,也可以 Device碌宴,或者來自于緩沖區(qū)隊(duì)列等等杀狡,完全是由 Media Object 對象的具體類型和應(yīng)用場景來配置。
??不同的 Media Object 對象實(shí)例贰镣,data source 和 data sink 的具體內(nèi)容是不一樣的呜象。
??對于 player 而言:
對于 recorder 而言:
引自:https://blog.51cto.com/ticktick/1771239
下面是一個播放音頻的完整示例:
#include <jni.h>
#include <string>
#include <android/log.h>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"test",__VA_ARGS__)
static SLObjectItf g_slObjEngine = NULL;
SLEngineItf CreatSLEngineItf()
{
//a 創(chuàng)建引擎對象
SLresult result = slCreateEngine(&g_slObjEngine, 0, 0, 0, 0, 0);
if (result != SL_RESULT_SUCCESS)
return NULL;
//b 實(shí)例化引擎對象
result = (*g_slObjEngine)->Realize(g_slObjEngine, SL_BOOLEAN_FALSE); //SL_BOOLEAN_FALSE等待對象創(chuàng)建
if (result != SL_RESULT_SUCCESS)
return NULL;
//c 獲取接口
SLEngineItf slEngineItf;
result = (*g_slObjEngine)->GetInterface(g_slObjEngine, SL_IID_ENGINE, &slEngineItf);
if (result != SL_RESULT_SUCCESS)
return NULL;
return slEngineItf;
}
//回調(diào)函數(shù)
void AudioCallBack(SLAndroidSimpleBufferQueueItf bf, void *context)
{
LOGE("AudioCallBack ");
static FILE *s_file = NULL;
static char *s_buf = NULL;
if (!s_buf) {
s_buf = new char[1024 * 1024];
}
if (!s_file) {
s_file = fopen("/sdcard/test.pcm", "rb");
}
if (!s_file) {
LOGE("fopen failed!");
return;
}
if (feof(s_file) == 0) {
int len = fread(s_buf, 1, 1024, s_file);
if (len > 0) {
(*bf)->Enqueue(bf, s_buf, len);
}
}
}
void playAudio() {
//1 創(chuàng)建引擎
SLEngineItf pEngineItf = CreatSLEngineItf();
if (pEngineItf)
{
LOGE("CreatSLEngineItf success!");
} else
{
LOGE("CreatSLEngineItf failed!");
}
//2 創(chuàng)建混音器
//----輸出混音器
SLObjectItf slObjMix = NULL;
SLresult result = (*pEngineItf)->CreateOutputMix(pEngineItf, &slObjMix, 0, 0, 0);
if (result != SL_RESULT_SUCCESS)
{
LOGE("CreateOutputMix failed!");
};
//----實(shí)例化
result = (*slObjMix)->Realize(slObjMix, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS)
{
LOGE("slObjMix Realize failed!");
};
SLDataLocator_OutputMix outmix = {SL_DATALOCATOR_OUTPUTMIX, slObjMix};
SLDataSink slDataSink = {&outmix, 0};
//3 配置音頻信息
//----創(chuàng)建緩沖隊(duì)列
SLDataLocator_AndroidSimpleBufferQueue bufQueue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 10};
//----音頻格式配置
SLDataFormat_PCM dataFormat_pcm = {
SL_DATAFORMAT_PCM,
2, //通道數(shù)
SL_SAMPLINGRATE_44_1, //采樣率
SL_PCMSAMPLEFORMAT_FIXED_16, // bitsPerSample
SL_PCMSAMPLEFORMAT_FIXED_16, // containerSize
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, //聲道
SL_BYTEORDER_LITTLEENDIAN //字節(jié)序,小端
};
//----播放器使用的結(jié)構(gòu)體
SLDataSource slDataSource = {&bufQueue, &dataFormat_pcm};
// 4 創(chuàng)建播放器
SLObjectItf slObjPlayer = NULL;
const SLInterfaceID itfIds[] = { SL_IID_BUFFERQUEUE }; //接口id
const SLboolean itfReqs[] = { SL_BOOLEAN_TRUE }; //接口開放
result = (*pEngineItf)->CreateAudioPlayer(pEngineItf, &slObjPlayer, &slDataSource, &slDataSink,
sizeof(itfIds) / sizeof(SLInterfaceID), itfIds, itfReqs);
if (result != SL_RESULT_SUCCESS)
{
LOGE("CreateAudioPlayer failed!");
} else {
LOGE("CreateAudioPlayer success!");
};
//實(shí)例化
(*slObjPlayer)->Realize(slObjPlayer, SL_BOOLEAN_FALSE);
//獲取接口
SLPlayItf slPlayItf = NULL;
result = (*slObjPlayer)->GetInterface(slObjPlayer, SL_IID_PLAY, &slPlayItf);
if (result != SL_RESULT_SUCCESS)
{
LOGE("slObjPlayer GetInterface failed!");
} else{
LOGE("slObjPlayer GetInterface success!");
};
//獲取緩沖隊(duì)列接口
SLAndroidSimpleBufferQueueItf slBufQueue = NULL;
result =(*slObjPlayer)->GetInterface(slObjPlayer, SL_IID_BUFFERQUEUE, &slBufQueue);
if (result != SL_RESULT_SUCCESS)
{
LOGE("slObjPlayer GetInterface BUFFERQUEUE failed!");
} else {
LOGE("slObjPlayer GetInterface BUFFERQUEUE success!");
};
//設(shè)置回調(diào)函數(shù),播放隊(duì)列為空的時候調(diào)用
//第二個參數(shù)是回調(diào)函數(shù) 第三個參數(shù)是 給回調(diào)函數(shù)傳的參數(shù)
(*slBufQueue)->RegisterCallback(slBufQueue, AudioCallBack, 0);
//設(shè)置狀態(tài) 播放
(*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PLAYING);
//啟動隊(duì)列回調(diào)
(*slBufQueue)->Enqueue(slBufQueue, "", 1);
}
參考:https://blog.csdn.net/u010141160/article/details/82871244
https://www.cnblogs.com/renhui/p/9565464.html
http://www.reibang.com/p/2b8d2de9a47b