banner
fwrite

fwrite

好好生活
twitter
github
email

Android オーディオシステム

  • アプリ
    音声アプリケーション

  • フレームワーク
    MediaPlayer と MediaRecorder、AudioTrack、AudioRecorder、AudioManager、AudioService および AudioSystem。

  • ライブラリ
    frameworks/av/media/libmedia、libaudioflinger、libmediaplayerservice

  • HAL
    AudioFlinger、AudioPolicyService。

2022-06-29-21-57-07

  • AudioPolicyService:APS は音声フレームワークのサービスで、main_audioserver が起動すると、AudioCommandThread と AudioPolicyClient、AudioPolicyManager が作成されます。主に AudioSystem によって binder 経由で呼び出され、AudioPolicyClient や AudioPolicyManager からも直接呼び出すことができます。ほとんどの操作は AudioPolicyManager に委任されます。

  • AudioPolicyClient:APC は AudioPolicyService の内部クラスです。入力と出力のオンオフ、ストリーム音量の設定、hal 層(audio_hw.cpp など)へのパラメータの渡しに使用されます。主に binder を介してプロセス間で AudioFlinger を呼び出して実際の操作を行います。AudioManager から mpClientInterface を介して呼び出すことができます。

  • AudioPolicyManager:APM は AudioPolicyService の主要な作業クラスで、AudioPolicyService のほとんどの操作を実行します。

  • AudioFlinger:AF は主に音声ミキシング出力を担当し、Audio システムのコアです。AudioTrack からのデータは最終的にここで処理され、Audio の HAL に書き込まれます。

  • DevicesFactoryHalLocal:名前に基づいて対応する hal モジュールをロードします。例えば、a2dp に関連する名前を渡すと、audio.a2dp.default.so にロードされます。

  • DevicesFactoryHalHidl:プロセス間で hidl hal モジュールをロードします。

  • DevicesFactoryHalInterface:サブクラス DevicesFactoryHalHybrid を作成するために使用されます。

  • DevicesFactoryHalHybrid:DevicesFactoryHalLocal または DevicesFactoryHalHidl を作成する選択をします。ここでは DevicesFactoryHalLocal を作成します。

  • DeviceHalLocal:プライベートメンバー audio_hw_device_t *mDev を介して、hal コードを直接呼び出し、底層パラメータの設定と取得、ストリームのオープンとクローズを行います。

  • StreamOutHalLocal:プライベートメンバー audio_stream_out_t *mStream を介して hal コードを直接呼び出し、ストリーム操作(start、stop、flush、pause など)を行います。また、write 関数を呼び出して音声データを hal 層に書き込みます。

  • AudioStreamOutSink:これは実際には StreamOutHalLocal のラッパーで、write 関数もありますが、StreamOutHalLocal を介して操作されます。

    重要なクラス図を添付します:

2022-06-29-21-57-45

Audio サービスの起動#

2022-06-29-21-58-13

  1. AudioFlinger と AudioPolicyService を作成します。
  2. Audio Config ファイル(audio_policy_configuration.xml)を解析し、サポートされている音声デバイスのリストと各入力出力経路の詳細パラメータを取得します。
  3. 解析したデバイスリストに基づいて、すべての Audio HAL ライブラリをロードします。
  4. すべての出力デバイスの outputStream をオープンし、PlaybackThread スレッドを作成します。
  5. すべての入力デバイスの inputStream をオープンし、RecordThread スレッドを作成します。

AudioTrack#

2022-06-29-21-58-33

Android の音声再生はすべて AudioTrack を介して行われ、MediaPlayer も最終的には AudioTrack を作成して再生します。AudioTrack を使用して音声を再生する主な手順は以下の通りです:

  1. AudioTrack を作成します。
  2. AudioTrack の play () メソッドを呼び出します。
  3. AudioTrack の write () メソッドを呼び出して音声データを書き込みます。

AudioTrack を作成する際の重要な点は、AudioPolicyManager を介して音声ルーティング経路を割り当て、サーバー側の AudioFlinger に対応する Track を作成するよう通知することです。

  • play () メソッドを呼び出すことは、作成した Track を mActiveTracks に追加し、スリープ状態の PlaybackThread スレッドをアクティブ化します。
  • write () メソッドを呼び出すことで、共有メモリを介してデータをサーバー側の AudioFlinger に書き込み、PlaybackThread がデータを受信してスレッドをアクティブ化し、データをミキシングなどの処理を行い、対応する Audio HAL に書き込み、Audio HAL がデータをドライバや他のデバイスに書き込みます。

音声ポリシー#

音声デバッグの参考:Android Audio

まず、stream_type、device、strategy の関係を理解する必要があります:

  • AudioSystem::stream_type:音声ストリームのタイプ
  • AudioSystem::audio_devices:音声入力出力デバイス、各ビットが一つのデバイスを表します。
  • AudioPolicyManagerBase::routing_strategy:音声ルーティング戦略

AudioPolicyManagerBase.getStrategy は stream type に基づいて対応する routing strategy 値を返し、AudioPolicyManagerBase.getDeviceForStrategy () は routing strategy に基づいて利用可能な device を返します。
まず、音声デバイスをロードする必要があります。音声デバイスの設定は system/etc/audio_policy.confvendor/etc/audio_policy にあり、設定ファイルにはさまざまな audio interface が表示され、AudioFlinger を介して音声デバイスがロードされます。
一定の優先順位に従って要件に合った Device を選択し、Device に適切な Output チャンネルを選択します。
getStrategy をオーバーロードして自分で Strategy を定義することができます。

routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);

音声データの取得#

PCM データを取得できる場所は三つあります:

  • 最初の場所 frameworks/av/media/libmedia/AudioTrack.cpp
nsecs_t AudioTrack::processAudioBuffer(){  
{
//releaseBuffer の前にダンプ 
releaseBuffer(&audioBuffer);  
}  
  • 二番目の場所 frameworks/av/services/audioflinger/Tracks.cpp
status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
        AudioBufferProvider::Buffer* buffer)
{
    // ダンプメソッドを追加
    ServerProxy::Buffer buf;
    size_t desiredFrames = buffer->frameCount;
    buf.mFrameCount = desiredFrames;
    status_t status = mServerProxy->obtainBuffer(&buf);
    buffer->frameCount = buf.mFrameCount;
    buffer->raw = buf.mRaw;
    if (buf.mFrameCount == 0 && !isStopping() && !isStopped() && !isPaused()) {
        ALOGV("underrun,  framesReady(%zu) < framesDesired(%zd), state: %d",
                buf.mFrameCount, desiredFrames, mState);
        mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
    } else {
        mAudioTrackServerProxy->tallyUnderrunFrames(0);
    }

    return status;
}
  • 三番目の場所 hardware/xxx/audio/tinyalsa_hal/audio_hw.c
static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
{  
	//ダンプメソッドを追加	 
}  

音声データの流れ#

Android システムの audio フレームワークには主に三つの再生モードがあります:low latency playback、deep buffer playback および compressed offload playback。

  • low latency /deep buffer モードでの音声データの流れ

2022-06-29-21-59-01

  • compressed offload モードでの音声データの流れ

2022-06-29-21-59-35

  • 音声録音

2022-06-29-21-59-56

  • 通話

2022-06-29-22-00-13

設定解析#

module の下には mixPorts、devicePorts および routes のサブセクションがあり、それぞれに複数の mixPort、devicePort および route のフィールドが含まれています。これらのフィールドは source と sink の二つの役割を示します:
devicePorts (source):実際のハードウェア入力デバイス;
devicePorts (sink):実際のハードウェア出力デバイス;
mixPorts (source):AudioFlinger の後のストリームタイプ、論理デバイスであり、物理デバイスではなく、AudioFlinger 内の PlayerThread に対応します;
mixPorts (sink):AudioFlinger の前のストリームタイプ、論理デバイスであり、物理デバイスではなく、AudioFlinger 内の RecordThread に対応します;
routes:devicePort と mixPorts のルーティング戦略を定義します。

2022-06-29-22-00-30

profile パラメータには音声ストリームの情報(ビット数、サンプリングレート、チャンネル数など)が含まれ、AudioProfile オブジェクトとして構築され、mixPort に保存され、module に格納されます。xml 内の devicePort には一般的に profile パラメータがなく、デフォルトの profile が作成されます。mixPort を Module に追加すると、分類が行われます:

source 役割は OutputProfileCollection mOutputProfiles に保存され、sink 役割は InputProfileCollection mInputProfiles に保存されます。
devicePort は HwModule::setDeclaredDevices () を呼び出して module の mDeclaredDevices に保存されます。

2022-06-29-22-00-49

HAL#

2022-06-29-22-01-05

Audio HAL の大まかなクラス図で、hal はファクトリーパターンを採用し、Local と HIDL モードに分かれ、最終的には audio_stream_out または audio_stream_in に呼び出され、各ベンダーによって実装された audio_hw.c に呼び出されます。

Bluetooth 接続の例#

2022-06-29-22-01-16

AudioService の handleDeviceConnection は AudioPolicyManager の setDeviceConnectionStateInt を呼び出します。

checkOutputsForDevice はすべての profile(出力)を検査し、各 profile に対応するスレッドが存在するかどうかを確認し、存在しない場合は作成します。checkOutputForAllStrategies は AudioTrack の書き込みデータソースを切り替えます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。