リアルタイム安全性
「リアルタイム安全」とは、同じ libsonare の DSP を、ライブの音声コールバック内でグリッチなく動かせる性質です。オンにする機能ではなく、音声経路が決して破ってはならない規則の集まりです。本ページはその規則と、libsonare がどう守るかを説明します。ストリーミング API は リアルタイムとストリーミング を参照してください。
音声コールバックには締め切りがある
音声は高優先度スレッド上でブロック単位で届き、各ブロックはスピーカーが必要とする前に — しばしば数ミリ秒以内に — 埋めなければなりません。一度でもその締め切りを逃すと、聞こえるクリック・ポップ・ドロップアウトになります。つまりコールバックには厳しいリアルタイム締め切りがあり、所要時間が無制限になり得るものはコールバック内で禁じられます。
コールバック内で禁じられること
| 禁止事項 | 音声を壊す理由 |
|---|---|
メモリ確保(new/malloc) | 予測できない時間ブロックし得る |
| ロック/ミューテックス | 他スレッド待ちで止まり得る |
| ファイル/ネットワーク I/O | レイテンシが無制限 |
| 無制限の処理全般 | 1 回の超過で締め切りを逃す |
規律はこうです — 遅い作業(確保、ファイル読み込み、セットアップ)はコールバックの外で済ませ、コールバックは事前に作ったバッファを読んで処理するだけにします。
libsonare が安全を保つ方法
libsonare のリアルタイム経路は、コールバックの規則を次の方法で守ります。
| 技法 | 意味 |
|---|---|
| バッファの事前確保 | 音声ブロックごとのメモリ確保を避ける |
| ロックフリーなパラメータ更新 | UI からの変更で音声スレッドを止めない |
| パラメータスムージング | 値の変化でクリックを出さない |
| デノーマル対策 | 減衰時の極小浮動小数点値による CPU スパイクを避ける |
これらにより、同じ DSP コードをオフラインでもライブでも動かせます。
AudioWorklet
ブラウザではリアルタイム音声は AudioWorklet で動きます。これはメインスレッドとは別の、音声処理専用のコンテキストです。
想定する流れは次の通りです。
- メインスレッドでオブジェクトを準備する。
- 準備済みの処理を AudioWorklet へ渡す。
- Worklet 内ではメモリ確保をせずにブロックを処理する。
サイトはこの経路を SAB フリーで動かします。つまり SharedArrayBuffer を使わないため、特別な COOP/COEP ヘッダは不要です。
libsonare がリアルタイム安全性をどう実装するか
ミキサーのストリップ・バス、RealtimeEngine、StreamAnalyzer は、リアルタイム安全なコアを共有します。主な要素は次のとおりです。
- 事前確保バッファ(ブロックごとの再利用向けの
Mixer.createRealtimeBuffer()を含む) - ロックフリーなパラメータ変更
- デノーマル対策
- クリックなしの変化のためのパラメータスムーザー
- 並列経路をそろえるプラグインディレイ補償
スレッドをまたぐ必要のある状態は、ロックフリーチャンネルで移され、直接読むのではなくテレメトリとして公開されます。そのため同じ DSP が、オフラインレンダリングでもブラウザの AudioWorklet 内でも、コード変更なしに動きます。