Android 拡張機能

OpenSL ES for Android は、リファレンス OpenSL ES 仕様を拡張することで、Android と互換性を持たせ、Android プラットフォームの機能と柔軟性を活用できるようにします。

Android 拡張機能の API の定義は、OpenSLES_Android.h と、これを含むヘッダー ファイル内にあります。これらの拡張機能の詳細については、OpenSLES_Android.h をご覧ください。このファイルは、インストール ルートの sysroot/usr/include/SLES ディレクトリにあります。特に記載のない限り、すべてのインターフェースは明示的です。

これらの拡張機能は Android 固有のものなので、他の OpenSL ES 実装へのアプリの移植性は制限されます。この問題を緩和するには、拡張機能を使用しないようにするか、#ifdef を使用してコンパイル時に拡張機能を除外します。

次の表は、Android OpenSL ES がオブジェクトの種類ごとにサポートしている Android 固有のインターフェースとデータロケータを示しています。セル内の「使用可」という値は、各オブジェクトの種類にインターフェースとデータロケータが使用できることを示します。

機能 オーディオ プレーヤー オーディオ レコーダー エンジン 出力ミックス
Android バッファキュー 使用可: ソース(デコード) 使用不可 使用不可 使用不可
Android 構成 使用可 使用可 使用不可 使用不可
Android エフェクト 使用可 使用不可 使用不可 使用可
Android エフェクト機能 使用不可 使用不可 使用可 使用不可
Android エフェクト センド 使用可 使用不可 使用不可 使用不可
Android シンプル バッファキュー 使用可: ソース(再生)またはシンク(デコード) 使用可 使用不可 使用不可
Android バッファキュー データロケータ 使用可: ソース(デコード) 使用不可 使用不可 使用不可
Android ファイル ディスクリプタ データロケータ 使用可: ソース 使用不可 使用不可 使用不可
Android シンプル バッファキュー データロケータ 使用可: ソース(再生)またはシンク(デコード) 使用可: シンク 使用不可 使用不可

Android 構成インターフェース

Android 構成インターフェースは、オブジェクトに対してプラットフォーム固有のパラメータを設定できるようにします。このインターフェースは、対応するオブジェクトをインスタンス化する前にアプリで使用できるという点で、他の OpenSL ES 1.0.1 インターフェースとは異なります。したがって、オブジェクトはインスタンス化する前に設定することができます。/sysroot/usr/include/SLES にある OpenSLES_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 のエフェクト、エフェクト センド、エフェクト機能の各インターフェースは、アプリで端末固有のオーディオ エフェクトをクエリして使用するための汎用メカニズムを提供します。端末メーカーは、自社が提供する端末固有のオーディオ エフェクトをすべて文書化する必要があります。

ポータブル アプリでは、オーディオ エフェクトに Android エフェクトの拡張機能ではなく OpenSL ES 1.0.1 API を使用する必要があります。

Android ファイル ディスクリプタ データロケータ

Android ファイル ディスクリプタ データロケータは、オーディオ プレーヤーのソースを、読み取りアクセス権限が付与されたオープン ファイル ディスクリプタとして指定できるようにします。データ形式は MIME にする必要があります。

アプリはファイル ディスクリプタを通じて APK からアセットを読み取るので、この拡張機能は特にネイティブのアセット マネージャーと併用すると役立ちます。

Android シンプル バッファキュー データロケータとインターフェース

OpenSL ES 1.0.1 リファレンス仕様では、バッファキューはオーディオ プレーヤーのみに使用でき、PCM や他のデータ形式と互換性があります。Android シンプル バッファキュー データロケータとインターフェースの仕様は、次の 2 つの例外を除けばリファレンス仕様と同じです。

  • Android シンプル バッファキューは、オーディオ レコーダーとオーディオ プレーヤーに使用できます。
  • これらのキューでは PCM データ形式のみを使用できます。

録音用に、アプリは空のバッファをキューに登録する必要があります。システムがバッファへのデータ書き込みを完了したことについて、登録済みのコールバックから通知が送信されたとき、アプリはそのバッファから読み取りを行うことが可能です。

再生は同じ方法で動作します。ただし、ソースコードの互換性を今後も保つため、アプリでは OpenSL ES 1.0.1 バッファキューではなく Android シンプル バッファキューを使用することをお勧めします。

バッファキューの動作

Android 実装には、再生が SL_PLAYSTATE_STOPPED 状態になると再生カーソルが現在再生中のバッファの先頭に戻るという、リファレンス仕様の要件が含まれていません。Android 実装は、その動作に準拠することも、再生カーソルの位置を変更しないままにすることもできます。そのため、アプリはどちらの動作が発生するのかを推測できません。したがって、SL_PLAYSTATE_STOPPED への移行後に BufferQueue::Clear() メソッドを明示的に呼び出す必要があります。そうすることで、バッファキューが既知の状態になります。

同様に、バッファキュー コールバックのトリガーが SL_PLAYSTATE_STOPPED への移行になるべきか、それとも BufferQueue::Clear() の実行になるべきかどうかを管理する仕様はありません。そのため、いずれかに対する依存関係を作成するのではなく、アプリが両方を処理できるようにすることをお勧めします。

オブジェクト作成時の動的インターフェース

便宜上、OpenSL ES 1.0.1 の Android 実装では、アプリはオブジェクトをインスタンス化するときに動的インターフェースを指定できます。これは、インスタンス化後に動的インターフェースを追加するのに DynamicInterfaceManagement::AddInterface() を使用する代わりとなります。

拡張機能のレポート

プラットフォームで Android の拡張機能がサポートされているかどうかクエリするためのメソッドは 3 つあります。そのメソッドは次のとおりです。

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

これらのメソッドはすべて ANDROID_SDK_LEVEL_<API-level> を返します。ここで、API-levelANDROID_SDK_LEVEL_23 などのプラットフォーム API レベルです。プラットフォーム API レベルが 9 以上であれば、プラットフォームは拡張機能をサポートしています。

オーディオを PCM にデコードする

このセクションでは、エンコードされたストリームを即座に再生することなく PCM にデコードする、サポート終了予定の、OpenSL ES 1.0.1 の Android 固有の拡張機能について説明します。次の表は、この拡張機能と代替手段を使用する際の推奨事項を示しています。

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 形式を検出するための準備については、デコードされた PCM データの形式をメタデータによって特定するをご覧ください。

OpenSL ES for Android の PCM デコード機能では、一時停止と最初のシークがサポートされています。音量調節、エフェクト、ループ処理、再生レートはサポートされていません。

プラットフォームの実装によっては、アイドル状態のままにできないリソースがデコードで必要になる場合があります。そのため、空の PCM バッファを十分に提供することをお勧めします。そうしないと、デコーダが飢餓状態になります。たとえば、アプリが Android シンプル バッファキュー コールバックから、別の空のバッファをキューに登録せず戻った場合に、この現象が発生する可能性があります。デコーダの飢餓状態の結果は明示されませんが、たとえば「デコードされた PCM データの削除」、「デコード処理の一時停止」、「デコーダの完全終了」などになります。

注: Android 4.x (API レベル 16–20)で実行されているアプリの場合、エンコードされたストリームを PCM にデコードするが即座に再生しないようにするには、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 フレームのストリームである。
  • アプリがこのストリームを管理する。データは、識別子が URI であるネットワーク リソースや、識別子がファイル ディスクリプタであるローカル ファイル内にはありません。

アプリは最初に、いっぱいになったバッファセットを Android バッファキューに登録する必要があります。各バッファには 1 つ以上の完全な ADTS AAC フレームが含まれています。各バッファが空になると、Android バッファキュー コールバックが発生します。コールバック ハンドラはバッファにデータを補充してキューに再登録してから戻る必要があります。アプリはエンコードされたバッファを追跡し続ける必要はありません。コールバック パラメータ リストには、次にキューに登録する必要があるバッファを示す十分な情報が含まれています。ストリームの最後は、EOS アイテムをキューに登録することによって明示的に示されます。EOS 以降、それ以上キューに登録することはできません。

デコーダの飢餓状態を避けるには、いっぱいになった ADTS AAC バッファを提供することをお勧めします。たとえば、アプリが Android バッファキュー コールバックから、別のいっぱいになったバッファをキューに登録せずに戻った場合に、この現象が発生します。デコーダの飢餓状態の結果は明示されません。

データソースを除けば、ストリーミング デコード メソッドはオーディオを PCM にデコードするで説明されているメソッドと同じです。

名前は似ていますが、Android バッファキューは Android シンプル バッファキューとは異なります。ストリーミング デコーダは、ADTS AAC データソース用の Android バッファキューと、PCM データシンク用の Android シンプル バッファキューの両方の種類のバッファキューを使用します。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)以降を実行しているアプリでは、単精度浮動小数点形式で 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;
詳細については、「オーディオのサンプリング」の浮動小数点オーディオをご覧ください。