JavaレイヤーのAudioTrackクラスから始めましょう。
I AudioTrack Javaクラスの変更説明
- これまではモノラルとステレオのみだったチャンネル数が、最大8チャンネルまで拡張されました。パラメータはCHANNEL_OUT_7POINT1_SURROUNDで、これを見たときは顎が外れました。これがどういうことなのか、私には理解できません。知っている負け犬コーダーがいたら教えてください。 もちろん、最終的な出力はデュアルチャンネルのままです。マルチチャンネルはダウンミキサーで処理します。
- 他にも変更点はありますが、それ以上ではありません。あの滝沢ローラのデビュー作のように、ただ鼻の穴が大きくなっただけではありません。
II AudioTrack JNIレイヤーの変更の説明
このレイヤーには、JNIレイヤーとAudioTrack自体が含まれます。
- JNIレイヤーの変更はあまりありません。
- Audio Nativeのコア・コードはframework/avの下に移動しました。そうです。これがJB Audioの大きな変更点の一つで、Audio Nativeのコアコードはすべてframework/avディレクトリに移動しました。
- AudioTrackは、それを使用するプロセスのスケジューリング優先度を制御する変数を追加します。再生中であれば、プロセスのスケジューリング優先度をANDROID_PRIORITY_AUDIOに設定します。モザイクを見たら必ずつぶやくように。ここでもちょっと言葉を濁します。シングルコアのCPUの場合、プライオリティを設定するのは馬鹿げています。 しかし、2コアや4コアが一般的になった今、スケジューリング面で遊ぶ時が来たのです。敗者コーダーの本当のテストは:マルチコア並列プログラミング、linux osの原則は、敗者学生を習得するために努力する必要があります。オーディオは、あなたの恣意によって荒らされることはそう簡単ではありません。また、ローエンドの携帯電話は、4.1を移植しないでください、これは本当にローエンド再生することはできません。
typedef enum {
AUDIO_OUTPUT_FLAG_NONE = 0x0, // 属性なし
AUDIO_OUTPUT_FLAG_DIRECT = 0x1, // this出力は直接トラックに接続します。
// 1つの出力ストリームへ:ソフトウェア・ミキサーなし
AUDIO_OUTPUT_FLAG_PRIMARY = 0x2, // this出力は、次の出力のプライマリ出力です。
// この値は一意でなければなりません。
// デフォルトで開かれ
// ルーティング、オーディオモード、ボリュームを受信
// 音声通話に関するコントロール。
// 別の場所で定義
AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8 // ディープオーディオバッファを使う ″==ディープバッファって一体何?このモザイク、ちょっと大きすぎませんか?よく見えません!
} audio_output_flags_t.
- AudioTrack.cppは全部で1600行強なので、簡単です!
OK、モザイクがいくつかかかっていますね。日本の大作映画を見るときは大抵モザイクに目を通しますが、オーディオを分析するときは違います。AudioFlingerの分析の次のステップにモザイク除去の望みをかけましょう!
III AudioFlingerの変更点
AFの主な作業工程に沿って、変更点を説明します:
- AFの作成(onFirstRef関数を含む
- openOutput 関数と MixerThread オブジェクトの作成
- AudioTrackはcreateTrack関数を呼び出します。
- AudioTrackはstart関数を呼び出します。
- AudioTrackcreateTrack関数の呼び出し
3.1 AFの作成とonFirstRef
まあ、特に変わったことはありません。ポイントは3つ:
- AudioTrackstart関数の呼び出し
3.2 openOutput関数
openOutput関数がキーとなり、旧友のMixerThreadやAudioStreamOutputなどが登場します。このサブ作業は4.0でも可能だったので、それほど大きな変化はありません。しかし、状況は変わり、旧友たちは劇的に変わりました。MixerThreadファミリーから始めましょう。
図1 PlaybackThreadファミリー
図1で少し説明します:
- ThreadBase は Thread から派生したもので、別のスレッドで実行されます。これは列挙型 type_t を定義しており、MIXER、DIRECT、RECORD、DUPLICATING などのサブクラスの型を表すのに使用されます。これは理解しやすいでしょう?
- ThreadBase の内部クラス PMDeathRecipient は、PowerManagerService からのデスメッセージをリッスンするために使用されます。PMSはSystemServiceの中で動作しており、SSがハングするとPMSもハングします。SSがハングすると、init.rcのルールでmediaserverも死ぬので、AudioFlingerも死にます。みんな一緒に死ぬので、速いです。では、このPMDeathRecipientを設定する大きな意味は何でしょうか? 
ThreadBaseの重要なサブクラスであるPlaybackThreadを見てみましょう。
- ミキサー・ジョブの現在の状態を反映するために、MIXER_IDLE、MIXER_READY、MIXER_ENABLED という列挙型 mixer_state が定義されています。 
- threadLoop_mixやprepareTracks_lなど、サブクラスの実装が必要なダミー関数がいくつか定義されています。これらのいくつかの関数の抽象化はまだ大丈夫です。しかし、変更点があまりにも大きいので、擁護するのは難しいです。 
- TrackクラスはVolumeProviderからの派生を追加し、ボリュームを制御するために使用されるVPです。前回の紹介によると、JBでのボリューム管理は以前よりずっと細かくなっています。 
- TimedTrackの新しい定義が追加されました。このクラスの役割は、先に述べたrtp aahに関連しています。このクラスが完成したら、学生は適切な調査を行い、殲滅戦を戦うことができます! 
次に図2を見てください。
図 2 MixerThread とその仲間たち
図2、簡単に:
- MixerThreadはPlaybackThreadから派生したもので、この関係は最初から変わることはありませんし、今後も変わらないと思います。 
- MTの最大の変更点は、いくつかの重要なメンバー変数です。その中で、ミキシングに使われるAudioMixerはお分かりでしょう。 
- スレッドであるSoakerオブジェクトを追加します。soakという接頭辞に最も関連するウェブスターの辞書の項目は、法外な金額を支払わせることです。コードをもう一度見てみましょう。soakerはCPUと遊ぶことに特化したスレッドであることがわかりました。その仕事は、CPU使用率を上げるために計算をし続けることです。その存在は、マルチコアCPUなどでの新しいAFフレームワークの効率をテストするためだと思われます。だから、ローエンドのスマートフォンの皆さん、JBで遊んではいけません。 
- ローエンドスマートフォンがJBをプレーすることはできないというもう一つの確かな証拠はこれです:MTの新しいFastMixerをご覧ください。わかりますか?JBでは、マルチコアスマートフォンでは、ミキシングはFastMixerがあるスレッドに入れることができ、もちろん、より速く、より効率的になります。 
上記は少し複雑だったので、MixerThread オブジェクトの作成で遭遇することの残りを以下に示します:
#p#
3.3 MixerThread の作成
NBAIOノート:
// このヘッダーファイルは抽象インターフェースのみを持ち、具体的な実装クラスは宣言されています。
// 実装は、すべてのメソッドでノンブロッキングにすべきです。
// 一般的に、実装はマルチスレッドである必要はありません。
// 例外が発生した場合は、特定の実装でその旨を記述します。
NBAIOは、特定の実装クラスに渡す必要のあるインターフェースを定義しているだけです。もちろん、読み書き関数はノンブロッキングである必要があり、実際の実装がブロッキングかどうかは実装者次第です。
個人的には、この部分はまだフレームワークとして成熟しきっていないように感じますが、NBIOの導入は学生にとって慎重さが要求され、比較的難しいものです。ここで、図3を通してNBAIOの内容の一部を見てみましょう。
図3 NBAIO関連コンテンツ
図3の説明は以下の通り:
- NBAIO_Sinkは出力エンドポイントに対応し、write関数とwriteVia関数を定義します。 writeVia関数は、データを取得するために内部的に呼び出されるコールバック関数をviaで渡す必要があります。同様に、データは2つのモードでプッシュ/プルされます。 
- MonoPipeとMonoPipeReaderを定義します。 Pipeはパイプのことで、MonoPipeはLINUXのIPC通信パイプとは何の関係もありませんが、このパイプの概念とアイデアを借用しているだけです。Audioの入力エンドポイント。 
switch { //kUseFastMixer は、FastMixer の使用を制御するために使用します:
mNormalSink = mOutputSink.
ブレイク
case FastMixer_Always: //デバッグのため、常に FastMixer を使用します。
mNormalSink = mPipeSink;
ブレイク
case FastMixer_Static://Static.これがデフォルトです。ただし、mPipeSink の正確な使用は initFastMixer によって制御されます。
mNormalSink = initFastMixer ? mPipeSink : mOutputSink;
ブレイク
}
readOutputParameters get.このコードは自分で勉強してください。もし理解したいのであれば、パラメータを指定して値を計算するのが一番です。
MixerThreadの作成はここで分析されています。いくつかの兄弟オブジェクトが何をするのかを学んでください.
3.4 createTrack と start の説明
また、このメカニズムの潜在的な利点は、AudioPolicy AudioRouteの作業をしている学生を解放することです。
AFでは、MediaSyncEventメカニズムはSyncEventで表現されます。
開始機能は、SyncEventの処理が追加されただけで、ほとんど変更されていません。
図 2 によると、FM(FastMixer の省略形)は内部データ構造として FastTrack を使用し、MT は Track を使用するため、ここでは 1 対 1 の対応関係にあります。
FM を使用するトラックは、mFastIndex を介してこの FastTrack を指します。
FastTrackとTrackの関係を把握するのはとりあえず十分で、その後のデータの流れについては詳細な検討が必要です。
MixerThread のワークフローを見てみましょう。この部分は力仕事です!
3.5 MixerThread ワークフロー
難しいのは、FastMixerがどのように機能するかということです。でも前もって言っておきますが、この機能はまだ完成していません。でも、負け犬の皆さん、あまり早く喜びすぎないでください。
もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ、もうすぐ。今、この未熟なものを見ておけば、後で成熟したものを見るときの精神的なプレッシャーも和らぐでしょう。
MTはthreadLoopでほとんどの作業が行われるスレッドで、この関数はベースクラスのPlaybackThreadで定義されています:
- PlaybackThreadのthreadLoopは、オーディオ処理の一般的な流れを定義し、詳細はいくつかのダミー関数を通してサブクラスに渡されます。 
- MTで大きく変わったのはprepareTracks_lで、まずFastMixタイプのTrackを扱い、TrackにTRACK_FASTフラグがセットされているかどうかを判定します。この部分の判定は少し複雑です。まず、FastMixer はステート マシンを維持し、さらにこの FastMixer は独自のスレッドで実行されるため、スレッドの同期が必要です。ステートは FastMixer のワークフローを制御するために使用されます。複数のスレッドが関係するため、オーディオのアンダーラン、オーバーラン状態も扱いにくい問題です。さらに、MTにはAudioMixerオブジェクトが付属しており、データのミキシングやダウンコンバートなど、超難易度の高いデジタルオーディオ処理を行います。つまり、ミキシングに関しては、統一された方法で管理できるため、事前準備作業はMTスレッドが行います。FastMixerに興味のある方は、prepareTracks_l関数について勉強してみてください。 
- TimedTrackクラスがあるので、AudioMixerのプロセス関数はタイムスタンプ、PTS、Presentationタイムスタンプと、エンコードとデコードの観点からDTS、Decodeタイムスタンプを持ちます。PTSとDTSには違いがあり、DTSはデコードタイムスタンプですが、エンコード時には未来のフレームに従って現在のフレームをエンコードする可能性があります。DTSはデコードのタイムスタンプですが、エンコード時に未来のフレームに合わせて現在のフレームをエンコードする可能性があるため、デコード時には未来のフレームを先にデコードしてから現在のフレームをデコードします。未来のフレームを先に再生することはできません。現在のフレームを先に再生し、その後に未来のフレームを再生するという順番でしか再生できません。PTS/DTSについては、IBP関連の知識を調べてください。MTの話に戻りますが、このPTSはHALが保持しているタイムスタンプであるはずのハードウェアハルオブジェクトから取得しています。このタイムスタンプの方が原理的に正確でしょう。 
- mTのthreadLoop_write関数の出力エンドポイントは、あの怪しいmNormalSinkで、それが空でなければ、そのwrite関数を呼び出します。NBAIO_Sinkのノンブロッキング書き込み関数を呼び出すことです。図2の分析によると、それはMonoPipeかもしれないし、古いAudioStreamOutputを使用するAudioStreamOutputSinkかもしれず、MonoPipeの書き込み関数は単なる内部のバッファです。出力です。この・・・・・・。何が問題なの? 
また、DulicatingThread,DirectOuptutThreadもあまり変わっていません。
IV FastMixer の動作に関する簡単な説明
以前は、ミキシングは FastMixer スレッドと MixerThread スレッドの両方で行われ、出力はまだ MixerThread で行われていると思っていました。上記の MonoPipe の解析から、この判断は正しくないかもしれません。
出力作業も FastMixer に渡し、MixerThread はミキシングの一部だけを行い、MonoPipe 経由で FastMixer スレッドにデータを渡します。FastMixer スレッドは、自身の FastTrack ミキシング結果と MT のミキシング結果の別のミキシングを行い、FastMixer によって出力されます。FastMixer スレッドは、自身の FastTrack ミキシング結果と MT のミキシング結果の再ミキシングを行い、FastMixer によって出力されます。
FMはFastMixer.cppで定義されており、その中核はThreadLoopです。AFのTrackの準備作業はすべてMTスレッドが行うので、FMのthreadLoopは基本的に状態に基づいて対応する処理を行います。
ここでの同期は、POSIX Mutex実装の基礎となる、非常に低レベルのLINUX futexを使用しています。このコードを書いた人がなぜミューテックスを使わなかったのかは分かりませんが、マルチスレッドによくここまで取り組んだものだと感心します!マルチスレッドのやり方を知らない人は、Posix MultiThread Programmingを勉強してください。
- また、FastMixer は内部的に AudioMixer をミキシングに使用しています。 
- それから......書き出します。 
FMの簡単な説明ですが、詳しく言うと、実機を持ってこないと直せないんです.4.1マシンをブラッシュアップしてくれる親切な人は、研究のために貸してください.
.今の兄弟は、FMとMTの一般的なワークフローを知っています。
V その他の変更
その他の変更点は以下の通り:
- デバッグを重視し、XXXDumpクラスを大量に追加。Google自身の開発でも多くの問題が発生したようです。単純な関数、誰がダンプしようと思うでしょうか?
- CPU使用率などのAFパフォーマンスを監視するAudioWatchdogクラスを追加。
まとめ
私が2.2AFに取り組んでいた頃、AudioFlingerは3k行強だったのを覚えていますし、JBはすでに9k行を超えています。他の補助クラスはカウントしていません。全体として、JBは以下のように変化しています:
- マルチコアリソースを最大限に活用することが重要なので、FastMixerは当然です。NBAIOインターフェイスも搭載。HALの書き方に大きなチャレンジがありそうな感じ。
- TimedTrackとSyncEventを追加することで、RTPや複数のプレーヤー間の同期をより良いユーザーエクスペリエンスで行えるようになります。
- ネイティブ・レイヤからJavaレイヤへの通知のためのインターフェイスを追加します。
その他いろいろ......。今日はここまで。





