AndroidのオーディオプラグインUIと実行形態についての覚書

Audio Plugins For Android (AAP) で曲がりなりにもGUIサポートを実装できたので、オーディオプラグインDSPGUIの連動形態について考えるようになった。

リモートプロセスを前提としたUI-DSP interop

AAPではWeb UIがDAWにとって自由にUIをコントロールでき、Androidのセキュリティプラクティスとしても問題がない推奨アプローチとなっているが、Web UIはホストプロセスで動作しており、たとえばGUI単体でサンプルファイルを開こうとするとプラグインプロセスではなくホストプロセスのパーミッションの範囲でしか開くことができない。プラグインが事前に用意していたコンテンツには全くアクセスできないことになる。そのため、ファイルを開く操作などはGUIではなくDSPのプロセスで行わせることになるが、そのためにはWeb UIとプラグインプロセス側のコードの間でインタラクションが必要になる。

これはLV2ではGUIDSP(オーディオスレッドで動いているコードという意味ではないのでやや雑な表現だが、「GUI以外」を示すものとしてはなあなあで使われてしまっている表現なので、ここでも単にDSPと書く)の間でプラグインのポートにAtomメッセージを書き込むLV2UI_Write_Functionを経由してやり取りすることになっている。Atomメッセージは任意の形式になるので、ここにUIとDSPで共通して理解できるコマンドのやり取りを「やま」「かわ」のレベルで自分で定義してやり取りしろ、というのがLV2のアプローチだ。実際には「開くファイル名のポート」にデータを渡されたらファイルを開く、くらいの運用になるし、典型的な操作はLV2:Patchを使えばいい。

実装アプローチとしては明確なのだけど、すべてのUI操作についてところどころこうやって「コマンド」を実装してやり取りしなければならないというのは、しかるべきアーキテクチャに沿って設計・実装するのでなければ、シンプルに面倒だ。こういうのはMV-Whateverのやり方で統合されていることが望ましそうだ。

UIのインプロセスホスティングの可能性

しかしそもそもプラグインUIがDAW上で自由にGUIを表示できればこの問題は生じないわけで、可能であればインプロセスで処理できたほうが開発体験が良くなるのではないか。現状ではSYSTEM_ALERT_WINDOWパーミッションがあればプラグインプロセスのUIを表示できるわけで、Androidでは技術的に困難というよりはOSポリシーの問題だ。AudioUnit V3の場合、App Extensionの拡張点としてGUIを作成していれば、DAWのプロセス上にいてもプラグインUIを表示できる。

AppleがApp Extensionについてこれを許しているのは、あくまでUIの実行はプラグインプロセス上で行っていて、AU拡張としてユーザーが明示的に許容したタイミングでしかUIを表示できないから、ということができるだろう。それならば、Androidでも同様の仕組みを作ることができるのではないか。

つまり「オーディオプラグインとしてシステムにアプリケーションのセットアップを登録できる」ようにすれば、SYSTEM_ALERT_WINDOWのようにアプリケーション側が任意のタイミングでUIをポップアップ表示することはできなくなり、DAWがオーディオプラグインUIを表示するとしたタイミングでのみ、ポップアップUIを表示することができる。この仕組みであれば、セキュリティ上の懸念はなくなるといえる。

これはAndroid上でIMEを有効にするためにSettingsで独自のパーミッションを有効化しないと使えないのと同じ仕組みだ。オーディオプラグインとして可視化されリストアップされるのであれば、SYSTEM_ALERT_WINDOWを表示しようとする他のアプリのリストを汚すことにもならず、明確に管理できる。

realtime audio priority over AIDL

オーディオプラグインアプリケーションをシステムに登録できることのメリットはもうひとつ考えられる。オーディオプラグインアプリケーションとしてDAWから接続されるServiceでは、オーディオ処理で必要となるリアルタイム優先度をもつBinderの接続を許容させることができる。realtime Binder IPCが一般に開放されていないのは、一般向けに開放するとすぐにリアルタイムスレッドが枯渇するからだと考えられるが、オーディオプラグインの処理にしか使えないようなIPCに開放することが、絞り込みとしては可能になる。

ただ、ここにどういう要件で絞り込みをかけられるかはまだ明確に見えてこない。AUv3の場合は、おそらくDSP処理もAudioUnit Extensionの拡張点としてAUの関数をオーバーライドすることで呼び出せるようにすることで、DAWのコードで直接IPCを呼び出させるのではなくAudioUnit FrameworkからDSP部分をリアルタイム優先度でIPCできるように実装したのだと考えられる。

AAPのようなオーディオプラグインの場合、リアルタイム優先度で呼び出されるべきはprocess()関数のみなので、この関数を含むServiceクラスが存在すればよいことになる。この関数が直接プラグイン開発者(あるいはプラグインフォーマット開発者)に開示される必要はない。あくまでフレームワークの一部として存在すればよいことになる。

ただ、従来のAndroid System上に存在しているリアルタイム優先度のサポートされたアプリケーションとは異なり、この仕組ではクライアント側だけでなくサービス側もユーザー実装が動作することになる。その中でどれだけ停止時間を含むコードが動作するかが未知数になるという事態は、Googleとしては避けたいところだろう。なので、この仕組み上で動作するAIDLでは最大実行時間に制約を設ける(そしてシステム上のデバッグ設定でデバッグアプリケーションについてはこの制約を無効化できる)といった対策が必要になるかもしれない。

オーディオプラグイン機構を「AudioBus相当」から「AUv3相当」にするために

これらの変更は、もちろんアプリケーションレベルでは不可能であり、Androidシステム(AOSP)に手を加えなければ実現しない。だからこれはだいぶ大掛かりなアイディアだ。とはいえ、AAP単独でできることにはこの辺に限界があって、現状ではiOSの世界でいうところのAudioBusのレベルでとどまっているということになる。ここから先に進むにはAOSPに手を出すしかなさそうだ。

もっとも、AAPは現時点でAudioBusのレベルに辿り着いているわけではない。GUI拡張を断片的にでも実装したことで、Android上のオーディオプラグインフォーマットとしては他の追随しない世界まで辿り着いたと思っているけど、まだ多くの部分が未完成だし、この領域に手を出す前にやることがある。それでも、ある程度の成果が出てきたら、次にやるべきことと、そのためのアプローチが見えてきたと思う。