Androidオーディオスタック:なぜ音楽がリサンプリングされるのか
Androidがオーディオをどう処理するかの詳細解説 — アプリからスピーカーまで。AudioFlingerが音楽をリサンプリングする理由とその対策を解説します。
Androidがオーディオを再生する仕組み
Androidスマートフォンが発するすべての音 — 通知、電話、ゲーム効果音、音楽 — は、耳に届く前に同じオーディオパイプラインを通過します。このパイプラインを理解することが、慎重にキュレーションしたロスレス音楽コレクションが期待ほど高音質に聴こえない理由を理解する鍵です。
標準的なAndroidオーディオパスは次のようになっています:
アプリ -> AudioTrack API -> AudioFlinger -> HAL(ハードウェア抽象化レイヤー) -> ハードウェア(スピーカー、DAC、Bluetoothラジオ)
音楽プレーヤーアプリがサウンドを生成するとき、AudioTrackを作成します(またはより新しいAAudio APIを使用しますが、同じシステムを経由します)。アプリはPCMオーディオサンプル — ソースファイルに含まれるサンプルレートとビット深度でのデコード済みオーディオデータ — をこのトラックに書き込みます。
これらのサンプルはその後AudioFlinger — Androidの中央オーディオミキシング・ルーティングサービス — に入ります。AudioFlingerはAndroidオーディオのトラフィックコントローラーです。システム上のすべてのアプリからオーディオストリームを取得し、それらをミックスし、システムレベルのエフェクト(システムボリュームなど)を適用し、正しい出力デバイスにルーティングします。ネイティブシステムサービスとして昇格した優先度で実行され、デバイス上のすべてのオーディオサンプルがこれを通過します。
AudioFlingerの下にはハードウェア抽象化レイヤー(HAL)があります。これはスマートフォンメーカーが作成したデバイス固有の変換レイヤーです。HALはAudioFlingerの出力を実際のハードウェアが期待するフォーマットに変換します — 内蔵DAC用のI2Sストリーム、外部DAC用のUSBオーディオパケット、ワイヤレスヘッドフォン用のエンコードされたBluetoothオーディオなど。
このアーキテクチャはシステム設計の観点からはエレガントです。どのアプリもハードウェアの詳細を気にせずにオーディオを再生でき、複数のオーディオストリームがシームレスにミックスされ、システムはルーティングとボリュームポリシーの制御を維持します。しかし音楽再生にとっては、問題を導入します。
AudioFlingerの問題
AudioFlingerは固定サンプルレートで動作します。ほとんどのAndroidデバイスでは、このレートは44,100 Hzまたは48,000 Hzのいずれかです — デバイスメーカーがHALを設定するときに決定し、通常システム稼働中に変更できません。最新のスマートフォンで最も一般的なデフォルトは48 kHzです。
この固定レートが存在するのは、AudioFlingerが根本的にミキサーだからです。複数のソース — 音楽、着信通知、ナビゲーションの案内、電話 — からのオーディオを単一の出力ストリームに結合する必要があります。オーディオのミキシングにはすべてのストリームが同じサンプルレートである必要があります。新しいストリームが開始されるたびにミキサーレートを動的に変更する(他のすべてのアクティブストリームを中断させる)のではなく、AudioFlingerは1つのレートを選択し、すべてをそれに合わせてリサンプリングします。
したがって、デバイス上のすべてのオーディオストリームがミキサーの固定レートにリサンプリングされます:
- 96 kHzハイレゾFLAC?48 kHzにダウンサンプリング。
- 48 kHzミキサーの44.1 kHz CDリップ?48 kHzにアップサンプリング。
- 48 kHzデバイスでの48 kHzポッドキャスト?変更なしでパススルー — 運が良かった。
- 176.4 kHz PCMに変換されたDSD64?48 kHzにダウンサンプリング。
GoogleはAudioFlingerを一般的なケース用に設計しており、正直言って、一般消費者向けスマートフォンとしては合理的なエンジニアリング判断です。しかし、オーディオファイル向けの再生のために設計されたわけではなく、リサンプリング品質は十分ではあるものの、忠実度が唯一の目標であれば選ばないものです。
AudioFlingerに組み込まれたリサンプラーは年々改善されています。初期のAndroidバージョンは低品質の線形補間器を使用していました。最新バージョン(Android 5.0以降)は合理的な結果を生み出すポリフェーズsinc リサンプラーを使用しています。しかし「合理的」と「透過的」は同じではありません — すべてのリサンプリング操作はどんなに小さくても量子化ノイズとエイリアシングアーティファクトの可能性を導入します。
サンプルレートネゴシエーション
状況は完全に絶望的ではありません。Androidはアプリが出力サンプルレートに影響を与えるメカニズムを提供していますが、結果は…一貫していません。
アプリがAAudio API(Androidの最新ネイティブオーディオインターフェース)を通じてオーディオストリームを作成する際、特定のサンプルレートをリクエストできます。Androidはこのリクエストを尊重しようとし、アプリは実際に付与されたレートを確認できます。デバイスのハードウェアとHALがリクエストされたレートをサポートしていれば、リサンプリングなしのネイティブ再生が得られる可能性があります。
Android 12以降はネイティブサンプルレート切り替えのサポートが向上しました。対応デバイスでは、特にUSBオーディオデバイスについて、アプリのリクエストに合わせてHAL出力レートを変更できます。
しかし、体験は苛立つほど一貫していません:
- SamsungはHAL実装でサンプルレートを固定値にロック。アプリが何をリクエストしても、ハードウェアは常に48 kHzで動作します。
- Pixelデバイスは一般的にネゴシエーションに対してより柔軟。しかしハードウェア世代によって動作が異なります。
- OnePlus?ファームウェアバージョンによります。これがAndroidオーディオ開発の現実です。
- 一部のOEMは動的なレート切り替えを許可しますが、特定の出力デバイスのみ(USB DACはOK、ヘッドフォンジャックはNG)。
- 一部のデバイスの開発者設定には「USBオーディオルーティング」トグルやサンプルレートオーバーライドがありますが、一般ユーザーからは隠され、標準化されていません。
実用的な結果として、アプリ開発者は特定のサンプルレートを取得することに頼れません。アプリはデバイスを探り、レートをリクエストし、実際に受信したものを確認し、それに応じて適応する必要があります。この探り-リクエスト-確認パターンが唯一の信頼できるアプローチです。
USB DACバイパス
USBオーディオクラス1およびクラス2デバイスは、Androidでの高品質オーディオ出力への最も有望なパスを提供します。USB DACを接続すると、AndroidのUSBオーディオドライバーがAudioFlingerがターゲットにできる新しいオーディオ出力デバイスを作成します。USB DACは通常複数のサンプルレートをサポートし、ホストにその機能を報告するため、ネイティブレート再生が得られる可能性が高くなります。
USB DACを使用したオーディオチェーンは次のようになります:
アプリ -> AAudio API -> AudioFlinger -> USB Audio HAL -> USB Audio Class Driver -> USB DAC
AudioFlingerがまだパスに存在していることに注目してください。デスクトップオペレーティングシステム — WindowsのWASAPI排他モードやmacOS CoreAudioのホグモード — がシステムミキサーを完全にバイパスできるのとは異なり、Androidはオーディオハードウェアへの真の排他アクセスを提供しません。AudioFlingerは常にアプリとデバイスの間に位置しています。常に。
しかし、星が揃えば、AudioFlingerはリサンプラーではなくパススルーとして機能できます:
- アプリがAAudio経由でトラックのネイティブサンプルレートをリクエスト。
- AudioFlingerがUSB Audio HALがそのレートをサポートするか確認。
- サポートされている場合、AudioFlingerはそのレートで出力を設定。
- アクティブなオーディオストリームがミキサーレートと一致する唯一のものであるため、リサンプリングは発生しない。
- サンプルはAudioFlingerを変更なしで通過し、USB DACに元のレートで到達。
これがAndroidでのビットパーフェクトに最も近い状態です。これが機能するには、同時に他のシステムサウンドやオーディオストリームがアクティブでないことも必要です — 他に再生中のものがあればAudioFlingerがミキシングに戻り、リサンプリングの可能性が出てきます。
Bluetooth:もう一つの変換レイヤー
BluetoothオーディオはAudioFlingerの上に完全に別の変換ステップを追加します。オーディオがシステムミキサーを通過した後、Bluetoothオーディオスタックに入り、ワイヤレス送信前にBluetoothオーディオコーデックにエンコードされます。
チェーンは次のようになります:
アプリ -> AudioFlinger -> Bluetooth コーデック エンコーダー -> ワイヤレス送信 -> ヘッドフォン/スピーカー
すべてのBluetoothコーデックはロッシーです。例外なし。Bluetoothリンクで利用可能な帯域幅は、高サンプルレートでの非圧縮オーディオには単純に不十分です。コーデックは利用可能な帯域幅内でどれだけ積極的に圧縮し、どの品質を達成するかが異なります。
SBC(Sub-Band Codec)は普遍的なベースラインです — すべてのBluetoothオーディオデバイスがサポートしています。約345 kbpsと48 kHzが上限です。
LDACはSonyが開発し、Android 8.0以降に搭載されており、990 kbpsと96 kHzで最高品質を提供します。最高設定では、LDACはほとんどのコンテンツに対して透過的と一般的に考えられています。しかし、それでもロッシー圧縮です。
すべてのBluetoothコーデック — LDAC、aptX、aptX HD、aptX Adaptive、AAC、SBC、LC3 — の詳細な比較については、Bluetoothオーディオコーデックガイドをご覧ください。
重要なポイント:AudioFlingerのリサンプリングをバイパスしても(ネイティブレート出力を取得することで)、Bluetoothエンコーディングはその後すべてを再圧縮します。Bluetooth経由のビットパーフェクト再生は物理的に不可能です。できる最善のことは、Bluetoothエンコーダーに最高品質のソース信号を供給し、最良の圧縮をさせることです。
EchoboxがAndroidオーディオスタックをどう扱うか
私たちはAndroidのオーディオシステムの制約と共に(そして回避して)動作するように、Echoboxを一から設計しました。Flutter、Rust、Zigの3層アーキテクチャにより、パイプラインのすべてのステージでオーディオに何が起こるかについて、ほとんどのアプリにはない制御が得られます。
アーキテクチャ
Flutterレイヤーは、見えるものとインタラクトするもの — ライブラリブラウザ、再生画面、設定 — を処理します。オーディオデータに直接触れることはありません。
Rustエンジンは中間に位置し、重い処理を担当します:ファイルデコード(Symphoniaライブラリ経由でFLAC、MP3、AAC、DSDなどのフォーマット)、サンプルレート変換、フォーマット正規化、オーディオ分析、状態管理。Rustを選んだのは、オーディオ処理が正確さと速度の両方を必要とするからです。
Zigレイヤーはリアルタイムオーディオコールバックを実行します — オペレーティングシステムが次のオーディオサンプルのチャンクを要求するたびに約10ミリ秒ごとに起動するコード。Zigコールバックはロックフリーリングバッファ(Rustエンジンが充填)からプリデコードされたサンプルを読み取り、7段階DSPチェーンを適用します:ReplayGain、プリアンプ、パラメトリックEQ、クロスフィード、ボリューム、グラフィックEQ、リミッター。
インテリジェントなサンプルレート処理
盲目的にオーディオを送信して最善を祈るのではなく、私たちはデバイスと能動的にネゴシエーションします:
- 一時的なAAudioストリームを開き、現在の出力デバイスに対するAndroidの最適レートを報告させることで、デバイスのネイティブレートを探る。
- 実際の再生ストリーム初期化時にそのレートをリクエスト。
- Androidが実際に提供したものを読み戻して、付与されたレートを確認。
- トラックのサンプルレートがデバイスレートと異なる場合、256タップFIRフィルターとBlackmanHarrisウィンドウを使用した高品質sinc補間リサンプラーでインテリジェントにリサンプリング。
ここでの重要な利点は二重リサンプリングの回避です。単純なアプリが44.1 kHz FLACをデコードし、48 kHzデバイスで44.1 kHzで出力すると、AudioFlingerが独自のアルゴリズムで48 kHzにリサンプリングします。私たちはデバイスが48 kHzで動作していることを検出し、自分たちで1回のクリーンで高品質なリサンプルを48 kHzに行います — AudioFlingerには変換するものが残りません。
ビットパーフェクトモード
USB DACユーザー向けに、EchoboxはAndroidの機能を限界まで押し上げるビットパーフェクトモードを提供します:
- DACからトラックの正確なネイティブサンプルレートをリクエスト。
- DSPチェーン全体をバイパス — EQなし、ボリューム調整なし、ReplayGainなし、リミッターなし。デコードされたサンプルは未変更のままパススルー。
- DACがリクエストされたレートをサポートできない場合、静かにリサンプリングするのではなく、明確なエラーで再生が失敗。
信号経路の透明性
おそらく最も重要なことに、Echoboxは何が起こっているかを正確に表示します。信号経路診断ディスプレイはオーディオチェーン全体をリアルタイムで表示します:ソースフォーマットとサンプルレート、リサンプリングがアクティブかどうかとその品質、どのDSPステージが動作しているか、デバイスが実際に動作しているレート、該当する場合はどのBluetoothコーデックが使用されているか。
ルート対応の動作
Echoboxは各出力デバイスをルートタイプ — ローカルスピーカー、USB DAC、Bluetooth、ネットワークレンダラー — で分類し、それに応じて動作を適応させます。Bluetoothが検出されると、ビットパーフェクトモードは自動的に無効になり(ロッシーワイヤレスコーデック経由では意味がないため)、EQやボリュームコントロールが使用できるようDSP処理はアクティブのままです。USB DACが接続されると、サンプルレートネゴシエーションとビットパーフェクトオプションの全範囲が利用可能になります。
ネットワークスピーカーへのUPnP/DLNAストリーミングでは、Echoboxはもう一つのインテリジェンスレイヤーを追加します — デバイスの機能を検出し、必要に応じてトランスコードします。オーディオスタックを超えた、音楽プレーヤーを真にオーディオファイルグレードにするものについては、オーディオファイル向けミュージックプレーヤーガイドで全体像をカバーしています。Android以外のプラットフォーム対応については、ロードマップもご確認ください。
Androidオーディオの現実
- AudioFlingerがボトルネック。Android上のすべてのサウンドがこのシステムミキサーを通過し、固定サンプルレート(通常48 kHz)で動作します。すべてのオーディオはハードウェアに到達する前にこのレートにリサンプリングされます。
- GoogleはAudioFlingerを一般用途向けに設計しました。通知、電話、音楽を1つのストリームにミックスするには共通のサンプルレートが必要であり、リサンプリングがそのトレードオフです。合理的な設計判断です — 私たちを念頭に置いて行われたものではありませんが。
- USB DACがAndroidでの品質への最善のパスを提供。複数のサンプルレートをサポートし、適切にアドレスされれば、AudioFlingerはリサンプリングなしでオーディオをパススルーできます。
- Androidは真の排他モードを提供しません。WindowsのWASAPI排他モードやmacOSのホグモードとは異なり、AudioFlingerを完全にバイパスする方法はありません。ミキサーは常にパスに存在しています。
- Bluetoothはすべての上にもう一つのロッシー変換を追加。Bluetoothコーデックはロスレスではなく、ワイヤレスでのビットパーフェクト再生は不可能です。
- Echoboxはデバイスレートを探り、必要に応じて高品質リサンプリングを実行し、ビットパーフェクトUSB DAC出力を提供し、信号経路診断で何が起こっているかを正確に表示することで、この複雑さを処理します。Rust/Zigアーキテクチャにより、ほとんどのアプリにはないオーディオパイプラインの制御が可能です。
- 正直な結論:Androidでは、アプリから耳まで音楽を不要な処理なしで届けるには、適切なドライバーサポートを持つUSB DACが必要か、システムがリサンプリングすることを受け入れるかのどちらかです。私たちはEchoboxを構築して、その現実をナビゲートするためのツールと透明性を提供します。