# 使用OpenSL ESå¼€å‘éŸ³é¢‘æ’æ”¾åŠŸèƒ½(C/C++) OpenSL ES全称为Open Sound Library for Embedded Systems,是一个嵌入å¼ã€è·¨å¹³å°ã€å…费的音频处ç†åº“。为嵌入å¼ç§»åŠ¨å¤šåª’ä½“è®¾å¤‡ä¸Šçš„åº”ç”¨å¼€å‘者æä¾›æ ‡å‡†åŒ–ã€é«˜æ€§èƒ½ã€ä½Žå»¶è¿Ÿçš„API。OpenHarmonyçš„Native API基于[Khronos Group](https://www.khronos.org/)å¼€å‘çš„[OpenSL ES](https://www.khronos.org/opensles/) 1.0.1 API 规范实现,开å‘者å¯ä»¥é€šè¿‡<OpenSLES.h>å’Œ<OpenSLES_OpenHarmony.h>在OpenHarmony上使用相关API。 ## 使用OHAudio替代OpenSL ES OpenHarmony上的OpenSL ES接å£ï¼Œæ˜¯æ—©æœŸSDK8版本开始æä¾›ï¼Œç”¨äºŽæ”¯æŒåº”用Native层音频开å‘的接å£ã€‚但éšç€ç‰ˆæœ¬æ¼”进,接å£å®šä¹‰çš„坿‰©å±•性ä¸è¶³ï¼Œä¸å†èƒ½æ»¡è¶³éŸ³é¢‘ç³»ç»Ÿçš„èƒ½åŠ›æ‹“å±•ï¼Œå› æ¤å½“å‰å·²ä¸å†æŽ¨è应用开å‘者继ç»ä½¿ç”¨æ¤æŽ¥å£è¿›è¡ŒéŸ³é¢‘功能开å‘,å¯èƒ½å˜åœ¨ä¸€äº›æŽ¥å£èƒ½åŠ›ä¸è¶³çš„缺陷。 在SDK10版本,OpenHarmony推出了OHAudio接å£ï¼Œå¹¶å°†ç³»ç»Ÿå…·å¤‡çš„æ‰€æœ‰éŸ³é¢‘åŠŸèƒ½éƒ½é€šè¿‡æ¤æŽ¥å£å¼€æ”¾ã€‚OHAudio接å£å·²èƒ½å¤Ÿè¦†ç›–OpenSL ES在OpenHarmonyä¸å·²æä¾›çš„æ‰€æœ‰èƒ½åŠ›ï¼Œå¹¶æ‹“å±•æ”¯æŒéŸ³é¢‘ç„¦ç‚¹äº‹ä»¶ï¼Œä½Žæ—¶å»¶ç‰æ–°ç‰ˆæœ¬ç‰¹æ€§ã€‚ OHAudioçš„å¼€å‘æŒ‡å—è§[使用OHAudioå¼€å‘éŸ³é¢‘æ’æ”¾åŠŸèƒ½(C/C++)](using-ohaudio-for-playback.md) 考虑到一些接入OpenHarmony较早的应用开å‘者,这里æä¾›äº†ä¸€ä»½OpenSL ES接å£åˆ‡æ¢åˆ°OHAudio的对照å‚考[OpenSL ES接å£åˆ‡æ¢OHAudioå‚考](replace-opensles-by-ohaudio.md),便于开å‘者能够更快的在新版本切æ¢åˆ°ä½¿ç”¨æ–°æŽ¥å£ã€‚ ## OpenHarmony上的OpenSL ES OpenSL ESä¸æä¾›äº†ä»¥ä¸‹çš„æŽ¥å£ï¼ŒOpenHarmony当å‰ä»…实现了部分[接å£](https://gitee.com/openharmony/third_party_opensles/blob/master/api/1.0.1/OpenSLES.h),å¯ä»¥å®žçŽ°éŸ³é¢‘æ’æ”¾çš„基础功能。 调用未实现接å£åŽä¼šè¿”回**SL_RESULT_FEATURE_UNSUPPORTED**, 当剿²¡æœ‰ç›¸å…³æ‰©å±•å¯ä»¥ä½¿ç”¨ã€‚ 以下列表列举了OpenHarmony上已实现的OpenSL ES的接å£ï¼Œå…·ä½“说明请å‚考[OpenSL ES](https://www.khronos.org/opensles/)规范: - **OpenHarmony上支æŒçš„SLInterfaceID**: | SLInterfaceID | 说明 | | -------- | -------- | | SL_IID_ENGINE | 通用引擎,æä¾›åˆ›å»ºæ’æ”¾å¯¹è±¡æŽ¥å£ | | SL_IID_PLAY | æä¾›æ’æ”¾çŠ¶æ€æŽ¥å£ | | SL_IID_VOLUME | æä¾›éŸ³é¢‘æ’æ”¾æµéŸ³é‡è°ƒèŠ‚å’Œè¯»å–æŽ¥å£ | | SL_IID_OH_BUFFERQUEUE | æä¾›éŸ³é¢‘æ’æ”¾æµæ•°æ®å›žè°ƒæ³¨å†ŒæŽ¥å£ | - **OpenHarmony上支æŒçš„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) - **OpenHarmony上支æŒçš„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) - **OpenHarmony上支æŒçš„Playback接å£ï¼š** - SLresult (\*SetPlayState) (SLPlayItf self, SLuint32 state) - SLresult (\*GetPlayState) (SLPlayItf self, SLuint32 \*pState) - **OpenHarmony上支æŒçš„Volume控制接å£**: - SLresult (\*SetVolumeLevel) (SLVolumeItf self, SLmillibel level) - SLresult (\*GetVolumeLevel) (SLVolumeItf self, SLmillibel \*pLevel) - SLresult (\*GetMaxVolumeLevel) (SLVolumeItf self, SLmillibel \*pMaxLevel) - **OpenHarmony上支æŒçš„BufferQueue接å£**: 以下接å£éœ€å¼•å…¥<OpenSLES_OpenHarmony.h>使用。 | æŽ¥å£ | 说明 | | -------- | -------- | | SLresult (\*Enqueue) (SLOHBufferQueueItf self, const void \*buffer, SLuint32 size) | æ ¹æ®æƒ…况将bufferåŠ åˆ°ç›¸åº”é˜Ÿåˆ—ä¸ã€‚<br/>å¦‚æžœæ˜¯æ’æ”¾æ“作,则将带有音频数æ®çš„bufferæ’入到filledBufferQ_队列ä¸ï¼›å¦‚果是录音æ“作,则将录音使用åŽçš„空闲bufferæ’入到freeBufferQ_队列ä¸ã€‚<br/>self:表示调用该函数的BufferQueue接å£å¯¹è±¡ã€‚<br/>bufferï¼šæ’æ”¾æ—¶è¡¨ç¤ºå¸¦æœ‰éŸ³é¢‘æ•°æ®çš„buffer,录音时表示已å˜å‚¨å®Œå½•音数æ®åŽçš„空闲buffer。<br/>size:表示buffer的大å°ã€‚ | | SLresult (\*Clear) (SLOHBufferQueueItf self) | 释放BufferQueue接å£å¯¹è±¡ã€‚<br/>self:表示调用该函数的BufferQueue接å£å¯¹è±¡å°†è¢«é‡Šæ”¾ã€‚ | | SLresult (\*GetState) (SLOHBufferQueueItf self, SLOHBufferQueueState \*state) | 获å–BufferQueue接å£å¯¹è±¡çжæ€ã€‚<br/>self:表示调用该函数的BufferQueue接å£å¯¹è±¡ã€‚<br/>state:BufferQueue的当å‰çжæ€ã€‚ | | SLresult (\*RegisterCallback) (SLOHBufferQueueItf self, SlOHBufferQueueCallback callback, void\* pContext) | 注册回调函数。<br/>self:表示调用该函数的BufferQueue接å£å¯¹è±¡ã€‚<br/>callbackï¼šæ’æ”¾/录音时注册的回调函数。<br/>pContextï¼šæ’æ”¾æ—¶ä¼ å…¥å¾…æ’æ”¾éŸ³é¢‘æ–‡ä»¶ï¼Œå½•éŸ³æ—¶ä¼ å…¥å°†è¦å½•制的音频文件。 | | SLresult (\*GetBuffer) (SLOHBufferQueueItf self, SLuint8\*\* buffer, SLuint32\* size) | æ ¹æ®æƒ…况获å–相应的buffer。<br/>å¦‚æžœæ˜¯æ’æ”¾æ“作,则从freeBufferQ_队列ä¸èŽ·å–空闲buffer;如果是录音æ“作,则从filledBufferQ_队列ä¸èŽ·å–æºå¸¦å½•音数æ®çš„buffer。<br/>self:表示调用该函数的BufferQueue接å£å¯¹è±¡ã€‚<br/>bufferï¼šæ’æ”¾æ—¶è¡¨ç¤ºç©ºé—²çš„buffer,录音时表示æºå¸¦å½•音数æ®çš„buffer。<br/>size:表示buffer的大å°ã€‚ | ## 完整示例 ### 在 CMake 脚本ä¸é“¾æŽ¥åЍæ€åº“ ``` cmake target_link_libraries(sample PUBLIC libOpenSLES.so) ``` å‚考以下示例代ç ï¼Œæ’æ”¾ä¸€ä¸ªéŸ³é¢‘文件。 1. æ·»åŠ å¤´æ–‡ä»¶ã€‚ ```cpp #include "SLES/OpenSLES.h" #include "SLES/OpenSLES_OpenHarmony.h" #include "SLES/OpenSLES_Platform.h" ``` 2. 使用slCreateEngine接å£å’ŒèŽ·å–engine实例。 ```cpp SLObjectItf engineObject = nullptr; slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr); (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); ``` 3. èŽ·å–æŽ¥å£SL_IID_ENGINEçš„engineEngine实例。 ```cpp SLEngineItf engineEngine = nullptr; (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); ``` 4. é…ç½®æ’æ”¾å™¨ä¿¡æ¯ï¼Œåˆ›å»ºAudioPlayer。 ```cpp SLDataLocator_BufferQueue slBufferQueue = { SL_DATALOCATOR_BUFFERQUEUE, 1 }; // 具体傿•°éœ€è¦æ ¹æ®éŸ³é¢‘æ–‡ä»¶æ ¼å¼è¿›è¡Œé€‚é… SLDataFormat_PCM pcmFormat = { SL_DATAFORMAT_PCM, 2, // é€šé“æ•° SL_SAMPLINGRATE_48, // é‡‡æ ·çŽ‡ SL_PCMSAMPLEFORMAT_FIXED_16, // éŸ³é¢‘é‡‡æ ·æ ¼å¼ 16, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN }; SLDataSource slSource = { &slBufferQueue, &pcmFormat }; SLObjectItf pcmPlayerObject = nullptr; (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slSource, &slSink, 0, nullptr, nullptr); (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE); ``` 5. èŽ·å–æŽ¥å£SL_IID_OH_BUFFERQUEUEçš„bufferQueueItf实例。 ```cpp SLOHBufferQueueItf bufferQueueItf; (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf); ``` 6. 打开音频文件,注册BufferQueueCallback回调。 ```cpp 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å®žä¾‹ï¼Œå¼€å§‹æ’æ”¾ã€‚ ```cpp SLPlayItf playItf = nullptr; (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &playItf); (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); ``` 8. 结æŸéŸ³é¢‘æ’æ”¾ã€‚ ```cpp (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); (*pcmPlayerObject)->Destroy(pcmPlayerObject); (*engineObject)->Destroy(engineObject); ```