適用於Android的OpenSL ES指南-OpenSL ES的Android擴展

翻譯自Android Extensionshtml

針對Android的OpenSL ES擴展了參考OpenSL ES規範,使其與Android兼容,並利用Android平臺的強大功能和靈活性。android

Android擴展的API定義在OpenSLES_Android.h和它包含的頭文件中。查閱OpenSLES_Android.h瞭解這些擴展的詳細信息。這個文件位於您的安裝根目錄下,在sysroot/usr/include/SLES目錄下。除非另有說明,全部接口都是顯式的。ios

這些擴展限制了應用程序到其餘OpenSL ES實現的可移植性,由於它們是特定於android的。您能夠經過避免使用擴展或使用#ifdef在編譯時排除它們來緩解這個問題。git

下表顯示了Android特定的接口和數據定位器及Android OpenSL ES支持的每種對象類型。單元格中的Yes值表示對象類型均可用的接口和數據定位器data locators。github

Feature Audio player Audio recorder Engine Output mix
Android buffer queue Yes: Source (decode) No No No
Android configuration Yes Yes No No
Android effect Yes No No Yes
Android effect capabilities No No Yes No
Android effect send Yes No No No
Android simple buffer queue Yes: Source (playback) or sink (decode) Yes No No
Android buffer queue data locator Yes: Source (decode) No No No
Android file descriptor data locator Yes: Source No No No
Android simple buffer queue data locator Yes: Source (playback) or sink (decode) Yes: Sink No No

Android配置接口

Android配置界面提供了一種爲對象設置特定於平臺的參數的方法。該接口不一樣於其餘OpenSL ES 1.0.1接口,由於您的應用程序能夠在實例化相應對象以前使用它;並且,您能夠在實例化對象以前配置它。OpenSLES_AndroidConfiguration.h頭文件,駐留在/sysroot/usr/include/SLES中,記錄瞭如下可用的配置鍵值:編程

  • 音頻播放器的流類型(默認SL_ANDROID_STREAM_MEDIA)。
  • 音頻記錄器的記錄配置文件(默認SL_ANDROID_RECORDING_PRESET_GENERIC)。

下面的代碼片斷展現瞭如何在音頻播放器上設置Android音頻流類型的示例:api

// CreateAudioPlayer and specify SL_IID_ANDROIDCONFIGURATION
// in the required interface ID array. Do not realize player yet.
// ...
SLAndroidConfigurationItf playerConfig;
result = (*playerObject)->GetInterface(playerObject,
    SL_IID_ANDROIDCONFIGURATION, &playerConfig);
assert(SL_RESULT_SUCCESS == result);
SLint32 streamType = SL_ANDROID_STREAM_ALARM;
result = (*playerConfig)->SetConfiguration(playerConfig,
    SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
assert(SL_RESULT_SUCCESS == result);
// ...
// Now realize the player here.
複製代碼

可使用相似的代碼來配置音頻記錄器的預設:bash

// ... obtain the configuration interface as the first four lines above, then:
SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
result = (*playerConfig)->SetConfiguration(playerConfig,
    RECORDING_PRESET, &presetValue, sizeof(SLuint32));
複製代碼

Android effects interfaces 效果接口

Android的效果、效果發送和效果功能接口爲應用程序查詢和使用特定於設備的音頻效果提供了通用機制。設備製造商應該記錄他們提供的任一設備特定的音頻效果。網絡

便攜應用應該使用OpenSL ES 1.0.1 api來實現音頻效果,而不是Android效果擴展。ide

Android file descriptor data locator 文件描述符數據定位器

Android文件描述符數據定位器容許您將音頻播放器的源指定爲具備讀權限的開放文件描述符。數據格式必須是MIME。

這個擴展與native asset manager結合使用特別有用,由於應用程序經過文件描述符從APK讀取assets。

Android simple buffer queue data locator and interface 簡單的緩衝隊列數據定位器和接口

在OpenSL ES 1.0.1參考規範中,緩衝區隊列只能用於音頻播放器,它們與PCM和其餘數據格式兼容。Android簡單緩衝隊列數據定位器和接口規範與參考規範相同,但有兩個例外:

  • 您可使用帶有錄音機和音頻播放器的Android簡單緩衝隊列。
  • 您只能對這些隊列使用PCM數據格式。

爲了記錄,您的應用程序應該排隊空緩衝區。當一個註冊回調發送一個通知,系統已經寫完數據到緩衝區,應用程序能夠從緩衝區讀取。

回放以一樣的方式工做。可是,爲了未來的源代碼兼容性,咱們建議應用程序使用Android簡單緩衝區隊列,而不是OpenSL ES 1.0.1緩衝區隊列。

buffer queue緩衝隊列行爲

Android實現不包括引用規範的要求,即當回放進入SL_PLAYSTATE_STOPPED狀態時,播放cursor返回到當前播放緩衝區的開始位置。該實現能夠順應該行爲,也能夠保持播放cursor的位置不變。所以,您的應用程序不能假定這兩種行爲都發生了。所以,在轉換到SL_PLAYSTATE_STOPPED以後,應該顯式調用BufferQueue::Clear()方法。這樣作將緩衝區隊列設置爲已知狀態。

相似地,緩衝區隊列回調的觸發器是否必須轉換爲SL_PLAYSTATE_STOPPED或執行BufferQueue::Clear(),也沒有規範來控制。所以,咱們建議您不要對其中一個建立依賴關係;相反,你的應用程序應該可以同時處理這兩種狀況。

對象建立時的動態接口

爲了方便起見,OpenSL ES 1.0.1的Android實現容許應用程序在實例化對象時指定動態接口。這是使用DynamicInterfaceManagement::AddInterface()的替代方案,以便在實例化後添加這些接口。

擴展報告 有三種方法能夠查詢平臺是否支持Android擴展。以下:

  • Engine::QueryNumSupportedExtensions()
  • Engine::QuerySupportedExtension()
  • Engine::IsExtensionSupported()

這些方法都返回ANDROID_SDK_LEVEL_<API-level>,其中API-level是平臺API級別;例如,ANDROID_SDK_LEVEL_23。平臺API級別爲9或更高意味着平臺支持擴展。

解碼音頻爲PCM格式

本節描述了OpenSL ES 1.0.1中一個不同意使用的android專用擴展,用於將編碼流解碼到PCM,而無需當即回放。下表給出了使用此擴展和替代方案的建議。

API level Alternatives替代方案
15 及如下 一種具備適當許可證的開源編解碼器
16 到 20 MediaCodec類或具備適當許可證的開源編解碼器
21 以上 NDK MediaCodec在<media/NdkMedia*.>頭文件,MediaCodec類,或具備適當許可證的開源編解碼器

注意:目前沒有關於MediaCodec API的NDK版本的文檔。可是,您能夠參考natvie-codec示例代碼。

標準音頻播放器回放音頻設備,指定輸出混合做爲數據接收器。Android擴展的不一樣之處在於,若是應用程序將數據源指定爲URI或使用MIME數據格式描述的Android文件描述符數據定位器,那麼音頻播放器將充當解碼器。在這種狀況下,數據接收器是一個使用PCM數據格式的Android簡單緩衝隊列數據定位器。

這個特性主要用於遊戲在轉換到新的遊戲級別時預加載它們的音頻assets,這與SoundPool類提供的功能相似。

應用程序最初應該在Android簡單緩衝區隊列中加入一組空緩衝區。而後,應用程序用PCM數據填充緩衝區。Android簡單的緩衝區隊列回調在每一個緩衝區被填滿後觸發。回調處理程序處理PCM數據,從新裝入如今爲空的緩衝區,而後返回。應用程序負責跟蹤解碼緩衝區(buffer);回調參數列表不包含足夠的信息來指示包含數據的緩衝區或接下來應該加入隊列的緩衝區。

數據源經過在流的末尾傳遞SL_PLAYEVENT_HEADATEND事件隱式地報告流的結束(EOS)。當應用程序解碼了它接收到的全部數據後,它就再也不調用Android簡單緩衝隊列回調。

數據槽sink的PCM數據格式一般與編碼的數據源在採樣率、聲道數和位深度方面匹配。可是,您能夠解碼到不一樣的採樣率、聲道數或位深度。有關檢測實際PCM格式的規定的信息,請看下面的經過元數據肯定解碼PCM數據的格式部分

OpenSL ES爲Android的PCM解碼功能,支持暫停和初始搜索;它不支持音量控制、效果、循環或播放速率。

根據平臺實現的不一樣,解碼可能須要不能閒置的資源。所以,咱們建議您確保提供足夠數量的空PCM緩衝區;不然,解碼器將捱餓。這可能發生,例如,若是您的應用程序從Android簡單的緩衝區隊列回調返回,而不排隊另外一個空緩衝區。解碼器餓死的結果是未知的,但可能包括:刪除解碼PCM數據,暫停解碼過程,或完全終止解碼器。

注意:對於運行在Android 4.x (API級別16-20)上的應用程序,解碼一個編碼流到PCM,但不當即回放,咱們建議使用MediaCodec類。對於在Android 5.0 (API level 21)或更高版本上運行的新應用程序,咱們建議使用NDK等效程序<NdkMedia*.h>。這些頭文件駐留在安裝根目錄下的media/目錄中。

解碼流式ADTS AAC轉爲PCM

若是數據源是使用MIME數據格式的Android緩衝隊列數據定位器,而數據接收器是使用PCM數據格式的Android簡單緩衝隊列數據定位器,則音頻播放器充當流解碼器。配置MIME數據格式以下:

  • 容器:SL_CONTAINERTYPE_RAW
  • MIME類型字符串:SL_ANDROID_MIME_AACADTS

該特性主要用於流媒體應用程序,這些應用程序處理AAC音頻,但須要在回放以前執行定製的音頻處理。大多數須要將音頻解碼到PCM的應用程序應該使用解碼音頻到PCM所描述的方法,由於該方法更簡單,能夠處理更多的音頻格式。這裏描述的技術是一種更專業的方法,只有在這兩種條件都適用時纔會使用:

  • 壓縮音頻源是包含在ADTS頭文件中的AAC幀流。
  • 應用程序管理這個流。數據不位於標識符爲URI的網絡資源中,也不位於標識符爲文件描述符的本地文件中。

應用程序最初應該在Android緩衝區隊列中加入一組已填充的緩衝區。每一個緩衝區包含一個或多個完整的ADTS AAC幀。每一個緩衝區清空後,Android緩衝區隊列回調會觸發。回調處理程序應該從新填充緩衝區並從新排隊,而後返回。應用程序不須要跟蹤已編碼的緩衝區;回調參數列表包含足夠的信息來指示下一個應該加入隊列的緩衝區。流的末尾經過對EOS項進行排隊顯式地標記。EOS後,不容許再排隊。

咱們建議您確保提供完整的ADTS AAC緩衝區,以免使解碼器捱餓。這可能發生,例如,若是您的應用程序從Android buffer queue回調返回,而不排隊另外一個完整的緩衝區。解碼器餓死的結果是未知的。

除了數據源以外,流解碼方法與解碼音頻到PCM的方法相同。

雖然名稱類似,但Android緩衝隊列與Android簡單緩衝隊列不一樣。流解碼器使用兩個緩衝隊列:ADTS AAC數據源的Android緩衝隊列和PCM數據槽的Android簡單緩衝隊列。有關Android緩衝隊列API的更多信息,請參閱安裝根目錄下docs/Additional_library_docs/openmaxal/目錄中的index.html文件。

經過元數據肯定已解碼的PCM數據的格式

SLMetadataExtractionItf接口是參考規範的一部分。可是,指示解碼PCM數據的實際格式的元數據鍵是Android特有的。OpenSLES_AndroidMetadata.h頭文件定義了這些元數據鍵。這個頭文件駐留在安裝根目錄下/sysroot/usr/include/SLES目錄中。

Object::Realize()方法執行完以後,元數據鍵索引當即可用。可是,在應用程序解碼第一個編碼數據以前,關聯的值是不可用的。一個好的實踐是,在調用Object::Realize方法後查詢主線程中的鍵索引,在第一次調用時讀取Android簡單緩衝隊列回調處理程序中的PCM格式元數據值。有關使用這個接口的示例,請參閱NDK包中的示例代碼

元數據鍵名是穩定的,可是鍵索引沒有被記錄,而且可能會發生更改。應用程序不該假定索引在不一樣的階段運行中是持久的,也不該假定多個對象實例在同一過程運行中共享索引。

浮點型數據

在Android 5.0 (API level 21)及更高版本上運行的應用程序能夠以單精度、浮點型向AudioPlayer提供數據。

在如下示例代碼中,Engine::CreateAudioPlayer()方法建立一個使用浮點數據的音頻播放器:

#include <SLES/OpenSLES_Android.h>
...
SLAndroidDataFormat_PCM_EX pcm;
pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
pcm.numChannels = 2;
pcm.sampleRate = SL_SAMPLINGRATE_44_1;
pcm.bitsPerSample = 32;
pcm.containerSize = 32;
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
...
SLDataSource audiosrc;
audiosrc.pLocator = ...
audiosrc.pFormat = &pcm;
複製代碼

在音頻採樣頁上閱讀關於浮點音頻的更多信息。


下一篇: 適用於android的OpenSL ES指南-編程注意事項

相關文章
相關標籤/搜索