WWDC Quick Look 💓 By SwiftGGTeam
Meet Audio Workgroups

Meet Audio Workgroups

元の動画を見る

ハイライト

2020 年の macOS と iOS は、リアルタイム オーディオ スレッド用のオーディオ ワークグループを提供し、複数のスレッドが同じオーディオ期限を共有していることをカーネルに知らせ、低レイテンシーの合成と信号処理における不具合のリスクを軽減します。

主要内容

プロのオーディオ アプリケーションを実行する場合、レイテンシーは抽象的な指標ではありません。シンセサイザーと信号処理コードは、非常に短いオーディオ サイクルで結果を生成する必要があります。以前は、開発者は独自のリアルタイム スレッドを作成し、複数の CPU コアに作業を分割できました。問題は、スケジューラが通常のスレッドのセットのみを認識し、同じ音声の期限を追いかけているわけではないことです。

Core Audio 自体によって管理される I/O スレッドは、各レンダリング サイクルの開始時間と終了時間をすでに知っています。オーディオ サーバーはクライアント スレッドを起動し、オーディオが生成されるのを待ってから、それをハードウェアに書き込みます。クライアントが遅すぎてスレッドが期限に間に合わない場合、ユーザーには不連続またはグリッチ (音声の中断) が聞こえます。

オーディオ ワークグループは、このセマンティクス層を補完します。ワークグループは 1 つ以上のスレッドで構成されます。マスター スレッド (メイン スレッド) は、各作業サイクルでカーネルに、作業がいつ開始され、いつ終了する必要があるかを伝えます。このように、パフォーマンス コントローラーは、「アプリケーションが使用するスレッドの数」に基づいて判断するだけでなく、これらのスレッドが同じリアルタイム オーディオ タスクで連携していることも認識します。

このセッションの焦点は狭いものです。アプリまたは Audio Unit が独自のリアルタイム オーディオ スレッドを作成する場合、これらのスレッドを正しいワークグループに追加する必要があります。システム フレームワークによって管理されるスレッドは自動的に追加されます。自分で作成したスレッドは明示的に処理する必要があります。

詳細

デバイス I/O 並列スレッド: デバイスのワークグループに参加します

(04:00) 典型的なシナリオは、アプリが 3 つの複雑なトラックを同時にレンダリングすることです。 I/O スレッドは最終ミックスを担当し、2 つの補助リアルタイム スレッドがトラックのコンテンツを並行して計算します。これらは I/O スレッドと同じ期限を使用しますが、デフォルトではデバイス ワークグループに含まれません。

解決策はまず装備を入手することですos_workgroup。 macOS では、HAL API を通じてオーディオ デバイスから取得できます。さまざまなプラットフォームでは、入出力オーディオ ユニット、AUHAL または AURemoteIO のプロパティからも取得できます。スレッドの開始後に呼び出されますos_workgroup_join、スレッドが終了する前に呼び出されますos_workgroup_leave

デバイス I/O 並列スレッドのワークフロー
1. デバイスの os_workgroup を取得します。
2. 自前の realtime thread で os_workgroup_join を呼び出します。
3. そのスレッドを I/O thread と同じ deadline のオーディオレンダリングに参加させます。
4. スレッド終了前に os_workgroup_leave を呼び出します。

キーポイント:

  • ステップ 1 のソースは、macOS の HAL API、または入出力オーディオ ユニット、AUHAL、または AURemoteIO にすることができます。
  • ステップ 2 はスレッド内で 1 回だけ実行する必要があり、その機能は現在のリアルタイム スレッドをデバイス ワークグループに追加することです。
  • ステップ 3 は、トランスクリプトの 3 つの複雑なトラック シナリオに対応します。I/O スレッドは補助スレッドを待ってから、最終結果を混合します。
  • ステップ 4 は、スレッドのライフサイクル終了後にワークグループ セマンティクスに残ることを避けるために、スレッドが終了する前に実行されます。

非同期リアルタイム スレッド: 独自の作業サイクルを作成する

(05:25) 別のタイプのワーカー スレッドはデバイス I/O と同期しません。彼らには独自のリズムと期限があります。たとえば、合成結果はバックグラウンドで事前に計算され、I/O スレッドに渡されて消費されます。期限が異なるため、デバイス ワークグループに参加できません。

このとき、独立したワークグループを作成する必要があります。セッションで与えられるAPIはAudioWorkIntervalCreateos_workgroup_interval_startそしてos_workgroup_interval_finish。マスター スレッドは、各サイクルの開始時に開始時刻と期限を報告し、サイクルの終了時に終了します。

非同期 realtime thread のワークフロー
1. AudioWorkIntervalCreate で独自の workgroup を作成します。
2. これらの realtime threads に os_workgroup_join を呼び出させます。
3. master thread は各作業サイクルで os_workgroup_interval_start を呼び出します。
4. startTime は mach_absolute_time から取得でき、deadline は startTime より大きい必要があります。
5. 各作業サイクルの終了時に os_workgroup_interval_finish を呼び出します。

キーポイント:

  • AudioWorkIntervalCreateデバイス I/O とは異なる頻度でワークグループを作成するために使用されます。 -os_workgroup_joinスレッドがワークグループに参加するときに一度だけ呼び出す必要があります。 -startTimeこれは現在時刻でも構いません。サイクルの実際の開始時間がわかっている場合は、最近の過去の時点を渡すこともできます。 -deadlineより大きくなければなりませんstartTime、両方のユニットはmach_absolute_time
  • セッションの特別な注意事項、思い込みはしないでくださいmach_absolute_timeはナノ秒です。使用する必要がありますmach_timebase_info変換頻度。 -os_workgroup_interval_finishこのサイクルが完了したことをカーネルに伝え、パフォーマンス コントローラーが完全な作業サイクル情報を取得できるようにします。

Audio Unit 補助スレッド: ホストのレンダリング コンテキストを観察します。

(07:03) ほとんどの Audio Unit は独自のリアルタイム スレッドを作成しません。いくつかの大きなプラグインは、レンダリング リクエストを複数のスレッドに分割します。プラグインが直面する問題は、ホストによって渡されるスレッド コンテキストが固定されていないことです。これは、デバイス I/O スレッドまたはホストの非リアルタイム ワーカー スレッドである可能性があります。

この問題を解決するために、Apple は 2020 年に導入しましたAURenderContextObserver。 Audio Unit は、レンダー コンテキスト オブザーバー プロパティを実装します。システムは、各レンダリング リクエストの前にこのブロックを呼び出し、os_workgroupコンテキスト構造体。プラグインはワークグループ内の変更を検出すると、独自の補助リアルタイム スレッドを新しいワークグループに追加します。

Audio Unit render context ワークフロー
1. Audio Unit は AURenderContextObserver property を実装し、block を返します。
2. システムは各 render request の前にこの block を呼び出します。
3. block が受け取る context struct には os_workgroup が含まれます。
4. context の workgroup が変わった場合、補助 realtime threads を新しい workgroup に参加させます。

キーポイント:

  • AURenderContextObserverこれは、Audio Unit 開発者によって実装されたレンダー コンテキスト オブザーバー プロパティです。
  • コンテキスト構造体内os_workgroup現在のレンダリング リクエストに対応するワークグループです。
  • ワークグループはレンダリングごとに変更される可能性があり、プラグインは初期化時に永続的な値をキャッシュできません。
  • 補助リアルタイム スレッドは、オブザーバーによって確認されたワークグループの変更に従い、現在のレンダリング リクエストのワークグループに再参加する必要があります。
  • ホストはオブザーバーを積極的に呼び出すべきではありません。セッションには、ホストがレンダリングするときにシステムがこれを自動的に完了することが明確に示されています。

スレッド数: ワークグループに並列処理の上限を与えます

(09:21) 並列ワーカー スレッドを作成するときは、CPU コアの数に基づいて盲目的にすべてのワーカー スレッドを開かないでください。オーディオ ワークグループによって提供os_workgroup_max_parallel_threads、使用可能な並列スレッドの数は、既知のワークグループに基づいて推奨されます。

推奨並列スレッド数のワークフロー
1. workgroup が判明してから os_workgroup_max_parallel_threads を呼び出します。
2. Audio Unit の初期化時には CPU core 数に合わせて worker threads を作成できます。
3. realtime render 段階では、API が推奨するスレッド数だけを使用します。

キーポイント:

  • os_workgroup_max_parallel_threadsワークグループがわかった後に呼び出す必要があります。
  • Audio Unit は、ワークグループを取得するためにリアルタイム レンダリング ステージまで待機する必要がある場合があります。
  • セッションの初期化時に CPU コアの数に応じてスレッドを作成し、レンダリング時に推奨された数のみが有効になるようにすることが推奨されます。
  • この数は、レンダリング サイクルごとの作業に実際に参加するスレッドの数であり、作成されたスレッドの総数と等しくありません。

重要ポイント

1. 大規模なコンポジターに並列レンダリング モードを追加する

  • 何をすべきか: 複数のオシレーター、フィルター、またはエフェクト チェーンを並列計算用の補助リアルタイム スレッドに分割します。
  • 実行する価値がある理由: セッションの説明 並列スレッドがデバイス ワークグループに参加すると、カーネルはそれらが I/O スレッドと同じ期限を共有することを認識します。
  • 開始方法: HAL、AUHAL、または AURemoteIO からデバイスを取得しますos_workgroup、スレッドの開始後に呼び出されますos_workgroup_join、アクティブ化の前後の過負荷またはグリッチの数を記録します。

2. オフライン事前計算のための独立したリアルタイム期間を確立する

  • 対処方法: デバイス I/O ワークグループに異なる期限を持つタスクを詰め込まないように、事前にオーディオ クリップを計算するワーカー スレッドに独立したケイデンスを作成します。
  • 実行する価値がある理由: セッションは、デバイスに対して並列スレッドとデバイスに対して非同期スレッドを明確に区別します。後者には独自のワークグループが必要です。
  • 開始方法: を使用しますAudioWorkIntervalCreateワークグループを作成し、マスター スレッドの各サイクルで呼び出すos_workgroup_interval_startそしてos_workgroup_interval_finish

3. 複雑な Audio Unit をさまざまなホストに適応させる

  • 内容: プラグインが別のホスト アプリで実行される場合、プラグインはホストの現在のレンダリング リクエストに対応するワークグループに動的に従います。
  • 実行する価値がある理由: セッションは、ホストがデバイス I/O スレッドを渡すのか、他のワーカー コンテキストを渡すのかを Audio Unit が認識しておらず、レンダリング時にのみ監視できることを指摘しています。
  • 開始方法: 実装AURenderContextObserver、このコンテキストを比較します。os_workgroup変更するかどうかに関係なく、その補助リアルタイム スレッドを新しいワークグループに切り替えます。

4. 推奨されるスレッド数を使用して CPU プレッシャーを制御する

  • 何をすべきか: 「事前に作成されたスレッド、定期的な有効化」スケジューリング レイヤーをリアルタイム オーディオ エンジンに追加します。
  • *なぜそれを行う価値があるのか​​: セッションによって与えられますos_workgroup_max_parallel_threads、現在のワークグループで使用する並列スレッドの数を決定するために使用されます。
  • 開始方法: 初期化中に固定ワーカー プールを作成し、レンダリング時にワークグループを取得した後に推奨される数をクエリし、現在のサイクルに参加する必要があるワーカーのみをウェイクアップします。

関連セッション

コメント

GitHub Issues · utterances