本頁詳細介紹了 OpenSL ES™ 的 NDK 實作與 OpenSL ES 1.0.1 的參考規範有何不同。使用規格說明中的程式碼範例時,您可能需要加以修改,才能在 Android 上執行。
除非另有說明,否則所有功能均適用於 Android 2.3 (API 級別 9) 以上版本。部分功能僅適用於 Android 4.0 (API 級別 14),請參閱相關說明。
注意:Android 相容性定義說明文件 (CDD) 中列有相容 Android 裝置的硬體和軟體需求。請參閱 Android 相容性詳細瞭解整體相容性計畫,並參閱 CDD 以取得實際 CDD 說明文件。
OpenSL ES 提供 C 語言介面,且可使用 C++ 存取此介面。此外,OpenSL ES 提供類似以下 Android Java API 音訊部分的功能:
和所有 Android 原生開發套件 (NDK) 一樣,適用於 Android 的 OpenSL ES 的主要用途是,協助實作可透過 Java 原生介面 (JNI) 進行呼叫的共用程式庫。NDK 不適用於編寫純 C/C++ 應用程式。不過,OpenSL ES 是功能全面的 API,我們預期您應只需使用此 API,就能滿足大部分音訊需求,無需向上呼叫在 Android 執行階段中執行的程式碼。
注意:Android 原生音訊 (高效能音訊) API 雖是以 OpenSL ES 為基礎,但並不是任何 OpenSL ES 1.0.1 設定檔 (遊戲、音樂,或電話) 的合格實作。這是因為 Android 並未實作任何一個設定檔所需的所有功能。Android 擴充功能頁面說明了 Android 行為與規範不同的所有已知情況。
從參考規範沿用的功能
OpenSL ES 的 Android NDK 實作項目從參考規格的功能集繼承了大部分功能,但有某些限制。
全域進入點
Android 版 OpenSL ES 支援 Android 規格中的所有全域進入點,包括:
slCreateEngine
slQueryNumSupportedEngineInterfaces
slQuerySupportedEngineInterfaces
物件和介面
下表列出了 OpenSL ES 的 Android NDK 實作支援的物件和介面。如果儲存格中為「是」,表示此實作項目支援該功能。
功能 | 音訊播放器 | 錄音工具 | 引擎 | 混音輸出 |
---|---|---|---|---|
低音強化 | 是 | 否 | 否 | 是 |
緩衝區佇列 | 是 | 否 | 不可以 | 否 |
緩衝區佇列資料定位器 | 是:來源 | 否 | 不可以 | 否 |
動態介面管理 | 是 | 可轉移 | 可轉移 | 是 |
效果傳送 | 是 | 否 | 不可以 | 否 |
引擎 | 否 | 否 | 是 | 否 |
環境回響 | 否 | 不可以 | 否 | 是 |
等化器 | 是 | 否 | 否 | 是 |
I/O 裝置資料定位器 | 否 | 是:來源 | 否 | 否 |
中繼資料擷取 | 是:解碼為 PCM | 否 | 不可以 | 否 |
靜音獨奏 | 是 | 否 | 不可以 | 否 |
物件 | 是 | 可轉移 | 可轉移 | 是 |
混音輸出定位器 | 是:接收器 | 否 | 不可以 | 否 |
播放 | 是 | 否 | 不可以 | 否 |
播放速率 | 是 | 否 | 不可以 | 否 |
預先擷取狀態 | 是 | 否 | 不可以 | 否 |
預設回響 | 否 | 不可以 | 否 | 是 |
錄製 | 否 | 是 | 否 | 否 |
跳轉 | 是 | 否 | 不可以 | 否 |
URI 資料定位器 | 是:來源 | 否 | 不可以 | 否 |
虛擬器 | 是 | 否 | 否 | 是 |
音量 | 是 | 否 | 不可以 | 否 |
下一節將說明部分上述功能的限制。
限制
表 1 中的功能存在特定限制,這些限制就是與參考規範不同的地方。本部分後續內容將介紹這些差異。
動態介面管理
Android 版 OpenSL ES 不支援 RemoveInterface
或 ResumeInterface
。
效果組合:環境回響和預設回響
在同一個混音輸出中,無法同時使用環境回響和預設回響。
如果平台預估 CPU 負載會過高,就可能忽略效果要求。
效果傳送
針對每個音訊播放器,SetSendLevel()
支援一個傳送電平。
環境回響
環境回響不支援 SLEnvironmentalReverbSettings
結構體的 reflectionsDelay
、reflectionsLevel
或 reverbDelay
欄位。
MIME 資料格式
MIME 資料格式只能與 URI 資料定位器結合使用,而且只能用於音訊播放器,此資料格式無法用於錄音工具。
OpenSL ES 的 Android 實作要求將 mimeType
初始化為 NULL
,或有效的 UTF-8 字串。您也必須將 containerType
初始化為有效值。如果沒有其他考量事項,例如移植到其他實作項目的可能性,或應用程式無法透過標頭辨識的內容格式,建議您將 mimeType
設為 NULL
,並將 containerType
設為 SL_CONTAINERTYPE_UNSPECIFIED
。
適用於 Android 的 OpenSL ES 支援以下音訊格式,但前提是 Android 平台也支援這些格式:
- WAV PCM。
- WAV alaw。
- WAV ulaw。
- MP3 Ogg Vorbis。
- AAC LC。
- HE-AACv1 (AAC+)。
- HE-AACv2 (增強型 AAC+)。
- AMR。
- FLAC。
注意:如需 Android 支援的音訊格式清單,請參閱支援的媒體格式。
在 OpenSL ES 的 Android 實作項目中處理上述及其他音訊格式時,存在以下限制:
- AAC 格式必須位於 MP4 或 ADTS 容器中。
- 適用於 Android 的 OpenSL ES 不支援 MIDI。
- WMA 不屬於 AOSP,我們尚未驗證 WMA 是否與適用於 Android 的 OpenSL ES 相容。
- OpenSL ES 的 Android NDK 實作不支援直接播放 DRM 或加密內容。如要播放受保護的音訊內容,您必須先在應用程式中進行解密,然後才能使用可強制執行任何 DRM 限制的應用程式播放此音訊內容。
與物件相關的方法
Android 版 OpenSL ES 不支援以下物件操控方法:
Resume()
RegisterCallback()
AbortAsyncOperation()
SetPriority()
GetPriority()
SetLossOfControlInterfaces()
PCM 資料格式
PCM 是唯一一種可用於緩衝區佇列的資料格式。支援的 PCM 播放設定具有下列特性:
- 8 位元無符號或 16 位元有符號。
- 單聲道或立體聲。
- 小端序位元組排序。
- 取樣率如下:
- 8,000 Hz。
- 11,025 Hz。
- 12,000 Hz。
- 16,000 Hz。
- 22,050 Hz。
- 24,000 Hz。
- 32,000 Hz。
- 44,100 Hz。
- 48,000 Hz。
Android 版 OpenSL ES 支援的錄製設定須視裝置而定。一般而言,無論何種裝置,都支援 16,000 Hz 單聲道/16 位元有正負號設定。
儘管名稱容易引起誤會,但 samplesPerSec
欄位的值是以 milliHz 為單位。為避免不小心使用錯誤的值,建議您使用其中一個專用的符號常數 (例如 SL_SAMPLINGRATE_44_1
),初始化這個欄位。
Android 5.0 (API 級別 21) 以上版本支援浮點資料。
播放速率
OpenSL ES 播放速率 代表物件呈現資料的速度,以正常速度的千分比 (或千分率) 表示。例如,一千分之 1,000 的播放速率為 1,000/1,000,即正常速度。「速率範圍」是一個封閉區間,表示一系列可能的播放速率。
因平台版本和實作不同,對播放速率範圍和其他功能的支援情況也存在差異。應用程式可在執行階段使用 PlaybackRate::GetRateRange()
或 PlaybackRate::GetCapabilitiesOfRate()
查詢裝置,確定這些功能。
對於 PCM 格式的資料來源,裝置一般支援相同的速率範圍。若是其他格式,則支援千分之 1000 到千分之 1000 的統一速率範圍,也就是說,統一速率範圍實際上是單一值。
錄製
Android 版 OpenSL ES 不支援 SL_RECORDEVENT_HEADATLIMIT
或 SL_RECORDEVENT_HEADMOVING
事件。
跳轉
SetLoop()
方法可進行全檔案循環。如要啟用循環播放,請將 startPos
參數設為 0,並將 endPos
參數設為 SL_TIME_UNKNOWN
。
緩衝區佇列資料定位器
若是具有緩衝區佇列資料定位器的音訊播放器或錄音工具,只支援 PCM 資料格式。
I/O 裝置資料定位器
如果您已將 I/O 裝置資料定位器指定為 Engine::CreateAudioRecorder()
的資料來源,則適用於 Android 的 OpenSL ES 將僅支援使用此定位器。請使用以下程式碼片段中包含的值,初始化裝置資料定位器:
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
URI 資料定位器
適用於 Android 的 OpenSL ES 只能將 URI 資料定位器與 MIME 資料格式結合使用,並且僅可用於音訊播放器,URI 資料定位器無法用於錄音工具。URI 只能使用 http:
和 file:
配置,不得使用 https:
、ftp:
或 content:
等其他配置。
我們尚未驗證 Android 平台是否支援含音訊的 rtsp:
。
資料結構
Android 支援以下 OpenSL ES 1.0.1 資料結構:
SLDataFormat_MIME
SLDataFormat_PCM
SLDataLocator_BufferQueue
SLDataLocator_IODevice
SLDataLocator_OutputMix
SLDataLocator_URI
SLDataSink
SLDataSource
SLEngineOption
SLEnvironmentalReverbSettings
SLInterfaceID
平台設定
適用於 Android 的 OpenSL ES 專為多執行緒應用程式而設計,並且符合執行緒安全要求。它支援每個應用程式一個引擎,每個引擎最多 32 個物件。可用的裝置記憶體和 CPU 可能會進一步限制可用物件數量。
系統會辨識以下引擎選項,但 slCreateEngine
會忽略這些選項:
SL_ENGINEOPTION_THREADSAFE
SL_ENGINEOPTION_LOSSOFCONTROL
在同一個應用程式中可以一起使用 OpenMAX AL 和 OpenSL ES。在這種情況下,內部存在一個共用引擎物件,而 OpenMAX AL 和 OpenSL ES 會共用 32 個物件的限制。應用程式應該建立兩個引擎,同時使用這兩個引擎,最後將其銷毀。實作項目會維護共用引擎的參考計數,以在第二次刪除作業時正確刪除引擎。
程式設計注意事項
OpenSL ES 程式設計注意事項提供了補充資訊,以確保可以正確實作 OpenSL ES。
注意:為了方便起見,我們在 docs/opensles/OpenSL_ES_Specification_1.0.1.pdf
中隨 NDK 一併提供了 OpenSL ES 1.0.1 規格。
平台問題
本節說明在支援這些 API 的初始平台版本中已知的問題。
動態介面管理
DynamicInterfaceManagement::AddInterface
無法運作。請改為在傳遞到 Create()
的陣列中指定介面,如環境回響的範例程式碼所示。
規劃未來版本的 OpenSL ES
Android 高效能音訊 API 以 Khronos Group OpenSL ES 1.0.1 為基礎。Khronos 已發布此標準版本的 1.1 修訂版本。修訂版本包含新功能和澄清說明,並校正了排版錯誤及部分不相容問題。大多數預期的不相容問題都相對輕微,或屬於 Android 不支援的 OpenSL ES 範疇。
只要遵循下方「二進位檔相容性規畫」一節所列出的準則,使用此版本開發的應用程式應該也能在日後推出的 Android 平台版本上執行。
注意:我們並未以與未來的原始碼相容為目標。也就是說,如果您升級至新版 NDK,則可能需要修改應用程式原始碼,以符合新版 API 的要求。我們預計這類變更大多是輕微修改,詳情請見下文。
二進位檔相容性規畫
建議您讓應用程式遵守以下準則,提升日後的二進位檔相容性:
- 僅使用 Android 支援的 OpenSL ES 1.0.1 功能中已有記錄的部分功能。
- 不要依賴特定結果程式碼來瞭解失敗作業,做好處理其他結果程式碼的準備。
- 應用程式回呼處理常式通常會在受限制的環境中執行。編寫的應用程式回呼處理常式應該能夠快速處理工作,並盡快傳回。請勿在回呼處理常式中執行複雜作業。例如,在緩衝區佇列完成回呼中,可以將另一個緩衝區排入佇列,但不要建立音訊播放器。
- 回呼處理常式應準備好進行不同頻率的呼叫,以及接收其他事件類型,並且應該忽略無法辨識的事件類型。傳回的回呼 已設定事件遮罩為已啟用的事件類型 且應準備好獲得呼叫 同時設定多個事件類型位元請使用「&」(而非「switch case」) 來測試每個事件位元。
- 使用預先擷取狀態和回呼做為一般進度指示,但不要依賴特定的硬式編碼填充等級或回呼序列。預先擷取狀態填充等級的含義,以及在預先擷取期間偵測到的錯誤行為可能會有所變化。
注意:詳情請參閱下方「緩衝區佇列行為」一節。
原始碼相容性規畫
如前文所述,Khronos Group 開發的下一版 OpenSL ES 預計會出現原始碼不相容問題。可能會出現以下方面的變動:
- 緩衝區佇列介面預計會有重大變動,尤其是在
BufferQueue::Enqueue
、slBufferQueueCallback
參數清單及SLBufferQueueState.playIndex
欄位名稱等方面。建議您將應用程式程式碼改用 Android 簡單緩衝區佇列。出於這個原因,在 NDK 隨附的範例程式碼中,我們已針對播放使用 Android 簡單緩衝區佇列。我們還使用 Android 簡單緩衝區佇列進行錄製和 PCM 解碼,不過這是因為標準 OpenSL ES 1.0.1 不支援錄製或解碼為緩衝區佇列資料接收器。 - 將會向由參照傳遞的輸入參數及做為輸入值的
SLchar *
結構欄位增加const
。您無需為此變更程式碼。 - 一些目前有正負號的參數將替換成無正負號的類型。您可能需要將參數類型從
SLint32
改為SLuint32
或類似類型,或者新增類型轉換。 Equalizer::GetPresetName
會將字串複製到應用程式記憶體,而不是傳回指向實作記憶體的指標。這將是一項重大變更,因此建議您避免呼叫此方法,或在隔離狀態下使用此方法。- 在結構類型中會有額外欄位。對於輸出參數,可以忽略這些新欄位;但對於輸入參數,則需要初始化新欄位。幸運的是,所有額外欄位預計都屬於 Android 不支援的領域。
- 介面 GUID 將會變更。請透過符號名稱 (而非 GUID) 參照介面,藉此避免依賴。
SLchar
將從unsigned char
變更為char
。這項變更主要會影響 URI 資料定位器和 MIME 資料格式。SLDataFormat_MIME.mimeType
將重新命名為pMimeType
,而SLDataLocator_URI.URI
將重新命名為pURI
。建議您使用以半形大括號括住並以半形逗號分隔的值清單 (而非欄位名稱) 來初始化SLDataFormat_MIME
和SLDataLocator_URI
,藉此確保您的程式碼不受此變更影響。範例程式碼就是使用了這種方法。SL_DATAFORMAT_PCM
不允許應用程式將資料的表示方式指定為有符號的整數、無符號的整數或浮點。Android 實作會假設 8 位元資料是無符號整數,而且 16 位元資料則是有符號整數。此外,samplesPerSec
欄位的名稱也不恰當,因為實際單位為 milliHz。我們預計將在下一版 OpenSL ES 中解決上述問題。新版本將提供新的擴充 PCM 資料格式,允許應用程式明確指定表示方法,並且會更正欄位名稱。由於這是新的資料格式,而目前的 PCM 資料格式仍可繼續使用 (雖然已淘汰),因此您不需要立即變更程式碼。