TASK 22: global audio sync offset (positive delay at the mixer out)

Adds AudioSyncOffsetMs (0..500ms, default 0) that delays the whole
interleaved-stereo mix so audio lands on the video when it runs ahead —
OBS's documented lip-sync fix. Positive-only: advancing audio needs a
video-side delay and is out of the audio layer's scope.

- Services/Audio/AudioSyncDelay.cs: pure delay line, flushed on Configure
- AudioMixer: Func<int> syncOffsetMs seam + delay applied post-limiter
- LayoutStore.Settings + MainViewModel.Audio/VM: load/save + binding
- PreviewPane mic bar: SYNC slider + status dot (IntToSyncBrushConverter)
- AudioSyncDelayTests: identity, negative/beyond-500 clamps, 10ms→960 samples

Reference (external scan): https://obs-versions.com/blog/how-to-fix-audio-delay-on-obs
(audio ahead => positive delay). Verified: build 0 warnings; 3/3 delay tests pass.
This commit is contained in:
2026-08-31 18:30:03 -07:00
parent 670fe3a10a
commit e8ff4df05f
12 changed files with 295 additions and 128 deletions
+12
View File
@@ -657,6 +657,18 @@
PreviewMouseLeftButtonDown="VolumeSlider_PreviewMouseLeftButtonDown"
PreviewMouseLeftButtonUp="VolumeSlider_PreviewMouseLeftButtonUp"
LostMouseCapture="VolumeSlider_LostMouseCapture"/>
<StackPanel Orientation="Horizontal" Margin="10,0,0,0" VerticalAlignment="Center"
ToolTip="Audio sync delay (ms): add a few ms so the mic/audio lands on the video when it runs ahead.">
<TextBlock Text="SYNC" FontSize="9" Foreground="#9898aa"
VerticalAlignment="Center" Margin="0,0,5,0"/>
<Slider Width="70" Minimum="0" Maximum="500"
Value="{Binding AudioSyncOffsetMs, Mode=TwoWay}"
VerticalAlignment="Center"
ToolTip="{Binding AudioSyncOffsetMs, StringFormat=Sync delay: {0} ms}"/>
<Border Width="8" Height="8" CornerRadius="4" Margin="6,0,0,0"
VerticalAlignment="Center"
Background="{Binding AudioSyncOffsetMs, Converter={StaticResource IntToSyncBrush}}"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Grid>