https://adventar.org/calendars/3353 7日目のエントリーです。
Oboeとは
OboeはC++環境向けのAndroidプラットフォーム向けのオーディオAPIです。
Androidでは、API Level 9 (Gingerbread) の時にネイティブのオーディオAPIレイヤーとしてOpenSL ESの実装が追加され、API Level 26(Oero)の時に低レイテンシーオーディオ処理をサポートするための新しくAAudio APIが追加されています。OboeはAAudio APIが利用可能な時にはAAudioを利用し、それ以外の時はOpenSL ESを利用する実装になっています。環境に応じて最適なバックエンドを選択する共通APIということになります。
なお、OboeはAPI Level 27以降にのみ含まれている部分のAAudio APIに依存しており、OboeがAAudioを利用する条件はAPI Level 27以降のみとなっています)。また、OpenSL ESドライバー実装も、サポートされているのはオーディオ設定まわりのAPIが追加されたAndroid 16(Jellybeanのひとつ)以降のみです。
Oboeのことを「低レイテンシーに対応したAPI」と紹介しているものがあるとしたら、それはほぼ間違いなくAAudioのことを指しています。Android 8.0以前では無関係な話です。
Oboeの機能は、概ねAAudio APIが提供するものと同様です。OpenSL ESにはAAudioには無いオプション設定がいくつかあるのですが、Android NDKに含まれるOpenSLESの実装ではサポートされていなかったものが多く、実質的にOpenSL ESを選択しなければならないような場面はほとんど無いでしょう。
Oboeは10月にバージョン1.0として正式版が公開され、GoogleのAndroid developers blogでも紹介されている程度には本気度と完成度が高いので、安心して使えると思います。(cmakeのビルドスクリプトではstaticでしかビルドできなかったりしますが…!)
シンプルなAPI
OboeはOpenSL ESに比べて極めてシンプルで使いやすいAPI設計になっています。具体例として、わたしがfluidsynth(これについてはまた別の日に書きます)でOpenSL ESを使用しているコードとOboeを使用しているコードを比較してみてください。というか、OpenSL ES APIの「どうしてこうなった」感…(VST3と似たような回りくどさですね)
- OpenSL ES: https://github.com/atsushieno/fluidsynth-fork/blob/e78021fad11e839570d134eebae2f2ecf6435b51/src/drivers/fluid_opensles.c#L142
- Oboe: https://github.com/atsushieno/fluidsynth-fork/blob/8f7c0e4c69e2c881c23d9fc48ae87c288d84b2c4/src/drivers/fluid_oboe.cpp#L159
- これはC++だから、というわけではありません。わたしがoboe-cというC APIを作って実装を書いた時のコードもまだまだ簡単なので、参考として挙げておきます: https://github.com/atsushieno/fluidsynth-fork/blob/e78021fad11e839570d134eebae2f2ecf6435b51/src/drivers/fluid_oboe.c#L128
Oboe(あるいはAAudio)の特徴的なオプション
AAudioおよびOboeによって新しく登場したAndroidネイティブオーディオのオプションとしては、次の2つが挙げられます。
(1) 共有モード: オーディオI/Oを排他的に獲得するか否かを指定します。Exclusiveで接続していると、他のアプリケーションから割り込まれたりはしなくなります。結果的にミキサーをひとつ経由しなくなる分レイテンシーが下がりますが、システム等によって割り込まれたりなどしてオーディオ接続が切断される可能性が高まるようです。早目の解放が想定されています。Sharedで接続しているとミキサーをひとつ経由するのでその分遅くなります。以下は公式サイトのドキュメントにある図です。
(2) パフォーマンスモード: LowLatencyモードとPowerSavingモードがあります。前者の低レイテンシーモードでは、バッファサイズを抑えることで、アプリケーションに対するオーディオデータ要求コールバックの頻度が上がり、オーディオの遅延は小さくなることが期待されます。逆にPowerSavingモードでは、コールバックの頻度が下がる分、バッテリーを過剰に使用しなくなります。デフォルトではその折衷的なNoneになっています。
これらをアプリケーションに合わせてうまく調整することで、最善のエクスペリエンスが期待できるでしょう。