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 Compatibility を、実際の CDD ドキュメントについては CDD をご覧ください。

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

あらゆる Android Native Development Kit(NDK)と同様、Android の OpenSL ES の主な目的は、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 のサポート

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

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

制限事項

表 1 の機能には、いくつかの制限事項が適用されます。これらの制限事項は、リファレンス仕様との差異になります。 本セクションではここから、これらの差異に関して説明します。

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

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

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

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

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

effect send

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

環境リバーブ

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

MIME データ形式

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

OpenSL ES の Android 実装では、mimeTypeNULL または有効な 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(enhanced 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 では、ロケータを Engine::CreateAudioRecorder() のデータソースとして指定した場合、I/O 端末データロケータの使用のみをサポートしています。次のコード スニペットに含まれている値を使用してデバイス データロケータを初期化してください。

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 をリリースしました。 改定版には新機能、明確化、誤植の訂正、非互換性が含まれます。 予期される非互換性のほとんどは、比較的軽微です。または、Android でサポートされない OpenSL ES の領域にあります。

このバージョンを使用して開発したアプリは、以下のバイナリの互換性に関する計画セクションで概説されているガイドラインに従っていれば、今後リリースされるバージョンの 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 データ形式は(サポートは終了しますが)引き続き利用することができます。そのため、すぐにコードを変更する必要はありません。