OpenSL ES for Android

このページでは、OpenSL ES™ の NDK 実装と OpenSL ES 1.0.1 のリファレンス仕様の違いについて詳しく説明します。仕様に含まれているサンプルコードを使用する場合、Android で動作させるためには変更が必要になることがあります。

特に記載のない限り、すべての機能を Android 2.3(API レベル 9)以降で利用することができます。Android 4.0(API レベル 14)でしか利用できない機能もありますが、そのような機能については明記されています。

注: Android Compatibility Definition Document(CDD)に、Android 互換デバイスのハードウェア要件とソフトウェア要件が列挙されています。全般的な互換性プログラムの詳細については、Android 互換性をご覧ください。また、実際の CDD ドキュメントについては、CDD をご覧ください。

OpenSL ES は、C++ を使用してアクセスすることも可能な C 言語のインターフェースを提供します。また、次に示す Android Java API のオーディオ部分に似た機能も公開します。

あらゆる Android Native Development Kit(NDK)と同様に、OpenSL ES for Android の主な目的は、Java Native Interface(JNI)を使用して呼び出す共有ライブラリの実装を容易にすることです。NDK は、純粋な C/C++ アプリケーションを作成するためのものではありません。ただし、OpenSL ES はフル機能を搭載した API なので、これだけで、Android ランタイムで実行しているコードへのアップコールを行わずにオーディオ ニーズのほとんどを実現できるはずです。

注: Android ネイティブ オーディオ(高性能オーディオ)の API は OpenSL ES に基づいていますが、どの OpenSL ES 1.0.1 プロファイル(ゲーム、音楽、スマートフォン)にも適合する実装ではありません。これは、Android が各プロファイルで必要な機能をすべて実装しているわけではないためです。Android が仕様とは異なる動作をする既知のケースについては、Android 拡張機能のページをご覧ください。

リファレンス仕様から継承された機能

OpenSL ES の Android NDK 実装はほとんどの機能セットをリファレンス仕様から継承しますが、制限がいくつかあります。

グローバル エントリ ポイント

OpenSL ES for Android は、Android 仕様のすべてのグローバル エントリ ポイントをサポートしています。そのエントリ ポイントには次のようなものがあります。

  • slCreateEngine
  • slQueryNumSupportedEngineInterfaces
  • slQuerySupportedEngineInterfaces

オブジェクトとインターフェース

次の表に、OpenSL ES の Android NDK 実装がサポートしているオブジェクトとインターフェースを示します。セルに「〇」が表示されている機能は、Android NDK 実装で利用することができます。

Android NDK のオブジェクトとインターフェースに対するサポート

機能 オーディオ プレーヤー オーディオ レコーダー エンジン 出力ミックス
バスブースト × ×
バッファキュー × × ×
バッファキュー データロケータ 〇: ソース × × ×
動的インターフェースの管理
エフェクト センド × × ×
エンジン × × ×
環境リバーブ × × ×
イコライザー × ×
I/O デバイス データロケータ × 〇: ソース × ×
メタデータ抽出 〇: PCM へのデコード × × ×
ミュートソロ × × ×
オブジェクト
出力ミックス ロケータ 〇: シンク × × ×
再生 × × ×
再生レート × × ×
プリフェッチ状態 × × ×
プリセット リバーブ × × ×
録音 × × ×
シーク × × ×
URI データロケータ 〇: ソース × × ×
バーチャライザー × ×
音量 × × ×

次のセクションでは、これらの機能の一部に対する制限事項について説明します。

制限事項

表 1 の機能には特定の制限事項が適用されます。これらの制限事項がリファレンス仕様との違いになります。ここからは、これらの違いについて説明します。

動的インターフェースの管理

OpenSL ES for Android は RemoveInterfaceResumeInterface をサポートしていません。

エフェクトの組み合わせ: 環境リバーブとプリセット リバーブ

1 つの出力ミックスに環境リバーブとプリセット リバーブの両方を含めることはできません。

プラットフォームは、CPU 負荷が高すぎると推測した場合、エフェクトのリクエストを無視することがあります。

エフェクト センド

SetSendLevel() は、オーディオ プレーヤーごとに 1 つの送信レベルをサポートしています。

環境リバーブ

環境リバーブは、SLEnvironmentalReverbSettings 構造体の reflectionsDelayreflectionsLevelreverbDelay の各フィールドをサポートしていません。

MIME データ形式

MIME データ形式は URI データロケータでのみ使用でき、対象はオーディオ プレーヤーだけです。MIME データ形式をオーディオ レコーダーに対して使用することはできません。

OpenSL ES の Android 実装では、mimeType を初期化して NULL または有効な UTF-8 文字列にする必要があります。また、containerType を有効な値に初期化する必要もあります。他の実装への移植性や、アプリがヘッダーで識別できないコンテンツ形式など、他の考慮事項がない限り、mimeTypeNULL に、containerTypeSL_CONTAINERTYPE_UNSPECIFIED に設定することをおすすめします。

次のオーディオ形式は、Android プラットフォームでも同様にサポートされる限り、OpenSL ES for Android でサポートされます。

  • WAV PCM
  • WAV alaw
  • WAV ulaw
  • MP3 Ogg Vorbis
  • AAC LC
  • HE-AACv1(AAC+)
  • HE-AACv2(拡張 AAC+)
  • AMR
  • FLAC

注: Android がサポートしているオーディオ形式の一覧については、サポートされているメディア形式をご覧ください。

OpenSL ES の Android NDK 実装でこのような形式を処理する際には、次の制限事項が適用されます。

  • AAC 形式は MP4 コンテナまたは ADTS コンテナに格納する必要があります。
  • OpenSL ES for Android は MIDI をサポートしません。
  • WMA は AOSP に含まれていないため、OpenSL ES for Android との互換性は未確認です。
  • OpenSL ES の Android NDK 実装は、DRM や暗号化されたコンテンツのダイレクト再生をサポートしません。保護されているオーディオ コンテンツを再生するには、DRM の制限事項を適用したまま、アプリで復号化してから再生する必要があります。

オブジェクト関連のメソッド

OpenSL ES for Android は、オブジェクトの操作用の以下のメソッドをサポートしていません。

  • 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

OpenSL ES for Android が録音用にサポートしている構成は、デバイスによって異なります。通常は、どのデバイスでも 16,000 Hz モノラル / 署名付き 16 ビットがサポートされます。

samplesPerSec フィールドの値はミリヘルツ単位です。名称に惑わされないようにしてください。間違った値を誤って使用しないよう、このフィールドを初期化することをおすすめします。初期化する場合、その目的で定義されているシンボリック定数のいずれか(SL_SAMPLINGRATE_44_1 など)を使用します。

Android 5.0(API レベル 21)以降では、浮動小数点データをサポートしています。

再生レート

OpenSL ES の「再生レート」は、オブジェクトがデータを表す速度を示します。これは通常速度の 1,000 分の 1(「パーミル」)で表されます。たとえば、再生レート 1,000 パーミルは 1,000/1,000 なので、通常速度です。「レート範囲」は、可能な再生レートの範囲を表す閉区間です。

再生レートの範囲などの性能に対するサポートは、プラットフォームのバージョンや実装によって異なる場合があります。アプリは、PlaybackRate::GetRateRange() または PlaybackRate::GetCapabilitiesOfRate() を使用してデバイスに照会することで、これらの性能を実行時に確認することができます。

デバイスは通常、PCM 形式のデータソースには同じレート範囲を、そして他の形式には 1,000 パーミル~1,000 パーミルの Unity レート範囲をサポートします。つまり、Unity レート範囲は事実上 1 つの値になります。

録音

OpenSL ES for Android は、SL_RECORDEVENT_HEADATLIMIT イベントと SL_RECORDEVENT_HEADMOVING イベントをサポートしていません。

シーク

SetLoop() メソッドは、ファイル全体のループを有効にします。ループを有効にするには、startPos パラメータを 0 に、endPos パラメータを SL_TIME_UNKNOWN に設定します。

バッファキュー データロケータ

バッファキュー データロケータを使用するオーディオ プレーヤーまたはオーディオ レコーダーは、PCM データ形式のみをサポートします。

I/O デバイス データロケータ

OpenSL ES for Android では、I/O デバイス データロケータを Engine::CreateAudioRecorder() のデータソースとして指定した場合、そのロケータの使用のみをサポートします。次のコード スニペットに含まれている値を使用してデバイス データロケータを初期化してください。

    SLDataLocator_IODevice loc_dev =
      {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
      SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
    

URI データロケータ

OpenSL ES for Android は、MIME データ形式の URI データロケータのみを使うことができ、対象はオーディオ プレーヤーのみになります。オーディオ レコーダーに 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

プラットフォームの構成

OpenSL ES for Android は、マルチスレッド アプリ向けに設計されており、スレッドセーフです。また、アプリごとに 1 つのエンジンを、エンジンごとに最大 32 個のオブジェクトをサポートしています。デバイスのメモリと CPU によって、使用可能なオブジェクトの数が少なくなる場合があります。

次のエンジン オプションは認識されますが、slCreateEngine では無視されます。

  • SL_ENGINEOPTION_THREADSAFE
  • SL_ENGINEOPTION_LOSSOFCONTROL

OpenMAX AL と OpenSL ES は、同じアプリで一緒に使用される場合があります。その場合、内部で 1 つのエンジン オブジェクトを共有します。また、32 個というオブジェクトの制限は OpenMAX AL と OpenSL ES で共有されます。アプリは両方のエンジンを作成、使用、破棄する必要があります。実装は、共有されているエンジンで参照カウントを保持するため、2 番目の破棄操作中に適切に破棄されます。

プログラミング メモ

OpenSL ES プログラミング メモでは、OpenSL ES を適切に実装するための補足情報を提供します。

注: ご参考までに、NDK の docs/opensles/OpenSL_ES_Specification_1.0.1.pdf に OpenSL ES 1.0.1 仕様のコピーを含めてあります。

プラットフォームの問題

このセクションでは、これらの API をサポートする初期プラットフォーム リリースの既知の問題について説明します。

動的インターフェースの管理

DynamicInterfaceManagement::AddInterface は動作しません。代わりに、環境リバーブのサンプルコードにあるように、Create() に渡される配列でインターフェースを指定します。

OpenSL ES の今後のバージョンに関する計画

Android の高性能オーディオ API は、Khronos グループの OpenSL ES 1.0.1 に基づいています。Khronos グループは、この標準の改定版である 1.1 をリリースしました。改定版には新機能、明確化、誤植の訂正、非互換性が含まれます。予期される非互換性のほとんどは、比較的軽微なものか、OpenSL ES の中でも Android のサポート対象外の部分に関するものです。

このバージョンを使用して開発したアプリは、以下のバイナリの互換性に関する計画で概説されているガイドラインに従っていれば、今後リリースされるバージョンの Android プラットフォームで動作するはずです。

注: 以下の計画は、将来にわたってソースコードの互換性を維持し続けることを目的としたものではありません。つまり、新しいバージョンの NDK にアップグレードする場合、新しい API に適合するようにアプリのソースコードを変更しなければならない場合があります。そのような変更のほとんどは、おそらく軽微なものになります。詳細については、以下をご覧ください。

バイナリの互換性に関する計画

今後のバイナリの互換性を向上するために、アプリで以下のガイドラインに従うことをおすすめします。

  • OpenSL ES 1.0.1 で文書化されている、Android がサポートしている機能のサブセットのみを使用する。
  • 失敗した操作については、特定の結果コードに依存せず、別の結果コードで対処するように備えておく。
  • アプリのコールバック ハンドラは通常、制限されたコンテキストで実行する。すばやく実行して可能な限り早く戻るよう記述しておく必要があります。コールバック ハンドラ内で複雑な操作を実行しないようにします。たとえば、バッファキュー完了コールバック内で、別のバッファをキューに登録してもかまいませんが、オーディオ プレーヤーは作成しないでください。
  • コールバック ハンドラは、追加のイベントタイプを受け取るために、頻繁に呼び出せるようにしておく。また、コールバックが認識しないイベントタイプは無視するようにする。有効なイベントタイプから成るイベントマスクで構成されているコールバックは、同時に設定された複数のイベントタイプ ビットで呼び出されるようにしておく必要があります。「&」を使用して、switch case ではなくイベントビットごとにテストしてください。
  • 進行状況の全般表示としてプリフェッチ状態とコールバックを使用するが、特定のハードコードされたフィルレベルやコールバック シーケンスに依存しないようにする。プリフェッチ状態のフィルレベルの意味と、プリフェッチ中に検出されるエラーの動作は、変わる可能性があります。

注: 詳細については、バッファキューの動作をご覧ください。

ソースの互換性に関する計画

すでに述べたように、Khronos グループが策定する次のバージョンの OpenSL ES では、ソースコードの非互換性が発生する見込みです。変更される可能性がある部分は次のとおりです。

  • バッファキュー インターフェースは大幅に変更される見込みです(特に、BufferQueue::Enqueue に関する部分、slBufferQueueCallback のパラメータ リスト、SLBufferQueueState.playIndex フィールドの名前)。代わりに、アプリコードで Android シンプル バッファキューを使用することをおすすめします。このため、NDK で提供しているサンプルコードでは、再生に Android シンプル バッファキューを使用しています(また、PCM への録音とデコードにも Android シンプル バッファキューを使用していますが、それは標準の OpenSL ES 1.0.1 がバッファキュー データシンクへの録音やデコードをサポートしていないためです)。
  • 参照によって渡される入力パラメータ、および入力値として使用される SLchar * 構造体フィールドには、const が追加される予定です。これに伴うコード変更は必要ないはずです。
  • 現在符号が付いているパラメータの一部は、符号なしの型で置き換えられる予定です。パラメータの型の変更(SLint32 から SLuint32 など)やキャストの追加が必要になる可能性があります。
  • Equalizer::GetPresetName は、実装メモリへのポインタを返すのではなく、文字列をアプリメモリにコピーします。これは大幅な変更になるため、このメソッドは呼び出さないようにするか、分離して使用することをおすすめします。
  • 構造体型にフィールドが追加されます。これらの新しいフィールドは、出力パラメータでは無視できますが、入力パラメータでは初期化する必要があります。幸い、これらのフィールドはすべて、Android のサポート対象外の範囲になる見込みです。
  • インターフェースの GUID が変更されます。依存関係を避けるために、GUID ではなくシンボリック名でインターフェースを参照してください。
  • SLcharunsigned char から char に変更されます。この変更は主に、URI データロケータと MIME データ形式に影響します。
  • SLDataFormat_MIME.mimeType の名前が pMimeType に、SLDataLocator_URI.URI の名前が pURI に変更されます。コードがこの変更の影響を受けないようにするために、SLDataFormat_MIME データ構造と SLDataLocator_URI データ構造の初期化には、フィールド名ではなく、中かっこで囲まれたカンマ区切りの値リストを使用することをおすすめします。この手法はサンプルコードで使用されています。
  • SL_DATAFORMAT_PCM は、データの表記を、符号付き整数、符号なし整数、または浮動小数点として指定することをアプリに許可しません。Android 実装は、8 ビットのデータを符号なし整数、16 ビットのデータを符号付き整数と想定します。また、実際の単位は milliHz なので、samplesPerSec フィールドの名称は誤っていることになります。これらの問題は、次のバージョンの OpenSL ES で対処されることが期待されています。次のバージョンの OpenSL ES では、アプリが表現を明示的に指定してフィールド名を訂正できるようにする、拡張された PCM データ形式が新しく導入される予定です。これは新しいデータ形式であり、現在の PCM データ形式は(サポートは終了しますが)引き続き利用することができます。そのため、すぐにコードを変更する必要はありません。