# 音訊

URL: https://flow.lanstar.dev/docs/architecture/audio

> 音訊輸出的實作。時鐘與同步見 [`engine.md`](/docs/architecture/engine#時鐘與-av-同步)，格式見 [`codecs.md`](/docs/codecs#音訊)。

`FlowAVAudio` 以 `AVAudioOutputFactory` 註冊 `AudioOutput`，由 AVAudioEngine 實作。

## 音訊圖

- **正常速度**：`AVAudioSourceNode`（interleaved Float32）直接接輸出，不經 mixer；音量由核心的 `AudioRenderSource` 套用。
- **倍速**：才接入 `AVAudioUnitTimePitch`（保持音高）。即使 bypass 它每個 IO 週期仍要 deinterleave 與 interleave，故只在倍速時留在圖中。
- **格式**：取樣率跟隨裝置，唯一的重取樣在解碼器（非即時執行緒）；最多雙聲道，由解碼器 downmix。
- **格式變更**：裝置的取樣率或聲道數改變時，output 以 `AudioRenderSource.outputFormatDidChange()` 通知核心，通知前後仍以舊格式輸出、由 output unit 轉換。核心停止輸出、以 `AudioOutput.updateFormat()` 取得新格式，重建 PCM ring 與音訊解碼器，並從播放位置以 `.exact` seek 重新解碼（同[解碼策略](/docs/architecture/engine#解碼策略)）。`AVAudioSourceNode` 會從建立時的格式轉換，故換格式時重建。

## Render

- render block 不捕捉任何值，經 `RenderSlots` 找到 `RenderState`，Swift 不在 render 執行緒做參照計數。
- 只呼叫 `AudioRenderSource`、讀 atomic 與運算：無鎖、無配置、無 log 與 signpost（硬即時，見[執行緒分級](/docs/architecture/engine#執行緒分級)）。
- 限制只在 render callback 內；Core Audio 每個 IO 週期在 callback 外自行上鎖一次，屬正常。
- 量測 callback 時把時間戳寫入 ring buffer，由其他執行緒發 signpost。

## 裝置與延遲

- **IO 緩衝**：1024 frames（預設的兩倍），IO 週期與其固定成本減半；多出的 10 ms 由延遲補償，只有暫停與音量變慢。依裝置範圍夾限，每次啟動重新套用。
- **延遲**：裝置、串流、safety offset、IO 緩衝，倍速時另加 time-stretch；啟動與裝置變更時重新查詢。
- **裝置變更**：引擎自行停止後在新裝置上重啟；格式不同時見[格式變更](#音訊圖)。停止期間換的裝置在 `start` 時檢查。

## 生命週期

- **暫停**：`engine.stop()`，釋放 IO 資源。不用 `pause()`：恢復後 host time 從暫停處繼續，落後暫停的時長。
- **切換速度、flush**：引擎停止時改圖或重設 time-stretch，再重啟；sample time 歸零，由核心重新錨定時鐘。
- **預熱**：模組啟用時背景建立一次 output unit，先付載入 audio HAL 與 plug-in 的成本（M4 Max 約 65 ms），不開裝置 IO（PERF-02）。
