Android 擴充功能

適用於 Android 的 OpenSL ES 擴展了 OpenSL ES 的參考規範,使其與 Android 相容,並充分運用 Android 平台的強大功能與靈活性。

如需有關 Android 擴充功能的 API 定義,請參見 OpenSLES_Android.h 及其中的標頭檔案;如要進一步瞭解這些擴充功能,請參閱 OpenSLES_Android.h。這個檔案位於安裝根目錄下的 sysroot/usr/include/SLES 目錄中。除非另有註明,否則所有介面皆為明確介面。

這些擴充功能會限制將應用程式移植至其他 OpenSL ES 實作的可攜性,因為這些擴充功能僅適用於 Android。如要避免這個問題,您是避免使用擴充功能,或是在編譯時使用 #ifdef 排除擴充功能。

下表列出 Android OpenSL ES 針對各種物件類型支援的 Android 專屬介面和資料定位器。如果儲存格中的值為「是」,則表示相應的介面和資料定位器可用於該物件類型。

功能 音訊播放器 錄音工具 引擎 混音輸出
Android 緩衝區佇列 是:來源 (解碼)
Android 設定
Android 效果
Android 效果功能
Android 效果傳送
Android 簡單緩衝區佇列 是:來源 (播放) 或接收器 (解碼)
Android 緩衝區佇列資料定位器 是:來源 (解碼)
Android 檔案描述元資料定位器 是:來源
Android 簡單緩衝區佇列資料定位器 是:來源 (播放) 或接收器 (解碼) 是:接收器

Android 設定介面

Android 設定介面可讓您為物件設定平台專屬參數。這個介面不同於其他 OpenSL ES 1.0.1 介面,可讓您的應用程式先使用此介面,再針對對應的物件執行個體化;因此,您可以先設定物件,然後再執行個體化。位於 /sysroot/usr/include/SLESOpenSLES_AndroidConfiguration.h 標頭檔案記錄了以下可用的設定金鑰和值:

  • 音訊播放器的串流類型 (預設為 SL_ANDROID_STREAM_MEDIA)。
  • 錄音工具的錄音設定檔 (預設為 SL_ANDROID_RECORDING_PRESET_GENERIC)。

以下程式碼片段範例說明瞭如何在音訊播放器上設定 Android 音訊串流類型:

// 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.

您可使用類似的程式碼來設定錄音工具的預設值:

// ... 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 效果介面

Android 的效果、效果傳送和效果功能介面針對應用程式提供通用機制,可供應用程式查詢及使用裝置專屬的音效。裝置製造商應將所提供的任何可用的裝置專屬音效記錄在文件之中。

可攜式應用程式應使用 OpenSL ES 1.0.1 API 提供音效,而非 Android 效果擴充功能。

Android 檔案描述元資料定位器

透過 Android 檔案描述元資料定位器,您可將音訊播放器的來源指定為具有讀取存取權的開放式檔案描述元。資料格式必須為 MIME。

由於應用程式可透過檔案描述元從 APK 讀取資產,因此這項擴充功能特別適合搭配原生資產管理工具使用。

Android 簡單緩衝區佇列資料定位器和介面

在 OpenSL ES 1.0.1 參考規範中,緩衝區佇列只能用於音訊播放器,並與 PCM 和其他資料格式相容。Android 簡單緩衝區佇列資料定位器和介面規範與參考規範相同,但有以下兩個例外狀況:

  • 您可以將 Android 簡單緩衝區佇列和錄音工具及音訊播放器搭配使用。
  • 這類佇列只能使用 PCM 資料格式。

如要錄製,應用程式必須將空緩衝區排入佇列。當註冊的回呼傳送系統已將資料寫入緩衝區的通知時,應用程式就可以從該緩衝區讀取資料。

播放功能的運作方式與此相同。為提升日後的原始碼相容性,建議應用程式使用 Android 簡單緩衝區佇列,而非 OpenSL ES 1.0.1 緩衝區佇列。

緩衝區佇列行為

參考規範要求當播放進入 SL_PLAYSTATE_STOPPED 狀態時,播放游標應回到目前播放緩衝區的開頭,而 Android 實作沒有滿足這個要求。此實作可以遵守該行為要求,也可以保持播放遊標位置不變。因此,您的應用程式無法推測哪一項行為會發生。這表示您必須在轉換至 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 級別 替代選項
15 及更低級別 具備適當授權的開放原始碼轉碼器
16 至 20 MediaCodec 類別或具備適當授權的開放原始碼轉碼器
21 及更高級別 <media/NdkMedia*.h> 標頭檔案中的 NDK MediaCodec、MediaCodec 類別或具備適當授權的開放原始碼轉碼器

注意:目前沒有 MediaCodec API 的 NDK 版本文件。不過,如需範例,您可以參照 native-codec 程式碼範例。

標準音訊播放器可以在音訊裝置上播放,並將混音輸出指定為資料接收器。Android 擴充功能的差別之處在於,如果應用程式已將資料來源指定為 URI,或者是使用 MIME 資料格式描述的 Android 檔案描述元資料定位器,則音訊播放器會是解碼器。在這類情況下,資料接收器是採用 PCM 資料格式的 Android 簡單緩衝區佇列資料定位器。

這項功能主要是讓遊戲在切換至新的遊戲關卡時預先載入其音訊資產,這與 SoundPool 類別所提供的功能相似。

應用程式最初應會將一組 Android 簡單緩衝區佇列中的空緩衝區排入佇列。之後,應用程式會在緩衝區中填入 PCM 資料。每個緩衝區都填入完畢後,Android 簡單緩衝區佇列回呼就會觸發。回呼處理常式會處理 PCM 資料並將目前的空緩衝區重新排入佇列,然後再傳回。應用程式負責追蹤已解碼的緩衝區;回呼參數清單的資訊不足,無法指出含有資料的緩衝區或者應該下一個排入佇列的緩衝區。

資料來源會在資料流結束時傳送 SL_PLAYEVENT_HEADATEND 事件以隱式回報資料流結尾 (EOS)。應用程式將所有收到的資料解碼後,就不會再對 Android 簡單緩衝區佇列回呼進行呼叫。

在取樣率、聲道數和位元深度方面,接收器的 PCM 資料格式通常與編碼的資料來源相符。不過,您可以解碼為不同的取樣率、聲道數或位元深度。如需用來偵測實際 PCM 格式的相關佈建資訊,請參閱 透過中繼資料決定已解碼的 PCM 資料格式

適用於 Android 的 OpenSL ES 的 PCM 解碼功能支援暫停和初始跳轉功能,不支援音量控制、效果、循環或播放速度。

取決於平台實作,要進行解碼時可能會要求資源不能處於閒置狀態。因此,建議您確定提供了足夠的空 PCM 緩衝區,否則會導致解碼器飢餓。例如,如果您的應用程式從 Android 簡單緩衝區佇列回呼傳回,但沒有將另一個空緩衝區排入佇列,就可能會發生這種情況。我們無法斷定解碼器飢餓的結果,可能包括:丟棄已解碼的 PCM 資料、暫停解碼程序,或立即終止解碼器運作。

注意 :如要將編碼的串流內容解碼為 PCM,但不要立即播放,則針對在 Android 4.x (API 級別 16 至 20) 上執行的應用程式,我們建議使用 MediaCodec 類別。如果是在 Android 5.0 (API 級別 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 影格串流。
  • 應用程式管理這個串流。資料「不」位於 ID 為 URI 的網路資源中,或 ID 為檔案描述元的本機檔案中。

應用程式最初應會將一組 Android 緩衝區佇列中已填滿的緩衝區排入佇列。每個緩衝區都包含一或多個完整的 ADTS AAC 影格。Android 緩衝區佇列回呼會在每個緩衝區都清空後觸發。回呼處理常式應會重新填入並重新排入緩衝區,然後再傳回。應用程式不需要追蹤已編碼的緩衝區;回呼參數清單包含充足的資訊,能夠指出應該下一個排入佇列的緩衝區。串流結尾會透過將 EOS 項目排入佇列來明確標記。在 EOS 之後,就無法再將更多內容排入佇列。

因此,建議您確定提供了填滿的 ADTS AAC 緩衝區,以免發生解碼器飢餓的情況。例如,如果您的應用程式從 Android 緩衝區佇列回呼傳回,但沒有將另一個填滿的緩衝區排入佇列,就可能會發生這種情況。我們無法斷定解碼器飢餓的結果。

在資料來源以外的所有方面,串流解碼方法與將音訊解碼為 PCM 中所述的方法相同。

儘管名稱相似,但 Android 緩衝區佇列和 Android 簡單緩衝區佇列並「不相同」。串流解碼器會使用上述兩種緩衝佇列:Android 緩衝區佇列用於 ADTS AAC 資料來源,Android 簡單緩衝區佇列則用於 PCM 資料接收器。如要進一步瞭解 Android 簡單緩衝區佇列 API,請參閱 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 級別 21) 和以上版本執行的應用程式,能為音訊播放器提供單精度浮點格式資料。

在下方的範例程式碼中,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;
如需瞭解浮點音訊相關資訊,請參閱音訊取樣頁面。