HarmonyOS音訊開發指導:使用OpenSL ES開發音訊播放功能

HarmonyOS開發者社群發表於2023-10-24

OpenSL ES全稱為Open Sound Library for Embedded Systems,是一個嵌入式、跨平臺、免費的音訊處理庫。為嵌入式移動多媒體裝置上的應用開發者提供標準化、高效能、低延遲的API。HarmonyOS的Native API基於 開發的  1.0.1 API 規範實現,開發者可以透過<OpenSLES.h>和<OpenSLES_OpenHarmony.h>在HarmonyOS上使用相關API。

HarmonyOS上的OpenSL ES

OpenSL ES中提供了以下的介面,HarmonyOS當前僅實現了部分 OpenSL ES 介面,可以實現音訊播放的基礎功能。

呼叫未實現介面後會返回 SL_RESULT_FEATURE_UNSUPPORTED,當前沒有相關擴充套件可以使用。

以下列表列舉了HarmonyOS上已實現的OpenSL ES的介面,具體說明請參考 規範:

●  HarmonyOS上支援的Engine介面:SLresult (*CreateAudioPlayer) (SLEngineItf self, SLObjectItf * pPlayer, SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired)

○  SLresult (*CreateAudioRecorder) (SLEngineItf self, SLObjectItf * pRecorder, SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired)

○  SLresult (*CreateOutputMix) (SLEngineItf self, SLObjectItf * pMix, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired)

●  HarmonyOS上支援的Object介面:SLresult (*Realize) (SLObjectItf self, SLboolean async)

○  SLresult (*GetState) (SLObjectItf self, SLuint32 * pState)

○  SLresult (*GetInterface) (SLObjectItf self, const SLInterfaceID iid, void * pInterface)

○  void (*Destroy) (SLObjectItf self)

●  HarmonyOS上支援的Playback介面:SLresult (*SetPlayState) (SLPlayItf self, SLuint32 state)

○  SLresult (*GetPlayState) (SLPlayItf self, SLuint32 *pState)

●  HarmonyOS上支援的Volume控制介面:SLresult (*SetVolumeLevel) (SLVolumeItf self, SLmillibel level)

○  SLresult (*GetVolumeLevel) (SLVolumeItf self, SLmillibel *pLevel)

○  SLresult (*GetMaxVolumeLevel) (SLVolumeItf self, SLmillibel *pMaxLevel)

HarmonyOS上支援的BufferQueue介面:以下介面需引入<OpenSLES_OpenHarmony.h>使用。

介面

說明

SLresult (*Enqueue) (SLOHBufferQueueItf self, const void *buffer, SLuint32 size)

根據情況將buffer加到相應佇列中。

如果是播放操作,則將帶有音訊資料的buffer插入到filledBufferQ_佇列中;如果是錄音操作,則將錄音使用後的空閒buffer插入到freeBufferQ_佇列中。

self:表示呼叫該函式的BufferQueue介面物件。

buffer:播放時表示帶有音訊資料的buffer,錄音時表示已儲存完錄音資料後的空閒buffer。

size:表示buffer的大小。

SLresult (*Clear) (SLOHBufferQueueItf self)

釋放BufferQueue介面物件。

self:表示呼叫該函式的BufferQueue介面物件將被釋放。

SLresult (*GetState) (SLOHBufferQueueItf self, SLOHBufferQueueState *state)

獲取BufferQueue介面物件狀態。

self:表示呼叫該函式的BufferQueue介面物件。

state:BufferQueue的當前狀態。

SLresult (*RegisterCallback) (SLOHBufferQueueItf self, SlOHBufferQueueCallback callback, void* pContext)

註冊回撥函式。

self:表示呼叫該函式的BufferQueue介面物件。

callback:播放/錄音時註冊的回撥函式。

pContext:播放時傳入待播放音訊檔案,錄音時傳入將要錄製的音訊檔案。

SLresult (*GetBuffer) (SLOHBufferQueueItf self, SLuint8** buffer, SLuint32* size)

根據情況獲取相應的buffer。

如果是播放操作,則從freeBufferQ_佇列中獲取空閒buffer;如果是錄音操作,則從filledBufferQ_佇列中獲取攜帶錄音資料的buffer。

self:表示呼叫該函式的BufferQueue介面物件。

buffer:播放時表示空閒的buffer,錄音時表示攜帶錄音資料的buffer。

size:表示buffer的大小。

完整示例

參考以下示例程式碼,播放一個音訊檔案。

1.      新增標頭檔案。

#include <OpenSLES.h>
#include <OpenSLES_OpenHarmony.h>
#include <OpenSLES_Platform.h>

2.      使用slCreateEngine介面和獲取engine例項。

SLObjectItf engineObject = nullptr;
slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
(*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);

3.      獲取介面SL_IID_ENGINE的engineEngine例項。

SLEngineItf engineEngine = nullptr;
(*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);

4.      配置播放器資訊,建立AudioPlayer。

SLDataLocator_BufferQueue slBufferQueue = {
    SL_DATALOCATOR_BUFFERQUEUE,
    0
};
// 具體引數需要根據音訊檔案格式進行適配
SLDataFormat_PCM pcmFormat = {
    SL_DATAFORMAT_PCM,
    2,                           // 通道數
    SL_SAMPLINGRATE_48,          // 取樣率
    SL_PCMSAMPLEFORMAT_FIXED_16, // 音訊取樣格式
    0,
    0,
    0
};
SLDataSource slSource = {&slBufferQueue, &pcmFormat};
SLObjectItf pcmPlayerObject = nullptr;
(*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slSource, null, 0, nullptr, nullptr);
(*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);

5.      獲取介面SL_IID_OH_BUFFERQUEUE的bufferQueueItf例項。

SLOHBufferQueueItf bufferQueueItf;
(*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf);

6.      開啟音訊檔案,註冊BufferQueueCallback回撥。

static void BufferQueueCallback (SLOHBufferQueueItf bufferQueueItf, void *pContext, SLuint32 size)
{
    SLuint8 *buffer = nullptr;
    SLuint32 pSize;
    (*bufferQueueItf)->GetBuffer(bufferQueueItf, &buffer, &pSize);
    // 將待播放音訊資料寫入buffer
    (*bufferQueueItf)->Enqueue(bufferQueueItf, buffer, size);
}
void *pContext; // 可傳入自定義的上下文資訊,會在Callback內收到
(*bufferQueueItf)->RegisterCallback(bufferQueueItf, BufferQueueCallback, pContext);

7.      獲取介面SL_PLAYSTATE_PLAYING的playItf例項,開始播放。

SLPlayItf playItf = nullptr;
(*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &playItf);
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);

8.      結束音訊播放。

(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
(*pcmPlayerObject)->Destroy(pcmPlayerObject);
(*engineObject)->Destroy(engineObject);


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70009402/viewspace-2990825/,如需轉載,請註明出處,否則將追究法律責任。

相關文章