Fix iOS background audio pacing
Build and test / test (macos-latest) (push) Waiting to run
Build and test / test (ubuntu-24.04) (push) Waiting to run
Build and test / test (windows-latest) (push) Waiting to run
Build and test / apple-client (push) Waiting to run

Sleep-paced threads stall for hundreds of milliseconds when iOS coalesces a
backgrounded app's wakeups, and the deadline resets that discarded the deficit
left the capture backlog queued until its ring overflowed: regular dropouts
that worsen the longer the app stays backgrounded. Pace both 20 ms hands-offs
from the AVAudioSourceNode render callback instead (mix via Audio.RunCycle
with deviceClockedAudio, capture handoff from the ring), wake the UDP sender
on a queue signal instead of a 1 ms poll, and let stalled consumers drop their
backlog to the buffer target instead of ratcheting it.
This commit is contained in:
2026-09-23 21:37:24 +02:00
parent 1487f2673b
commit f348574bc1
9 changed files with 273 additions and 42 deletions
@@ -132,6 +132,16 @@ public class PublishServerScriptTests
Assert.DoesNotContain("Task.Delay(10", screen);
Assert.Contains("MaximumCaptureCallbackFrames = 16_384", microphone);
Assert.DoesNotContain("Math.Ceiling(4_096 * 48_000", microphone);
// Both 20 ms hands-offs run from the AVAudioSourceNode render callback: sleep-paced
// threads coalesce when the app is backgrounded and glitch the call after several minutes.
string model = await File.ReadAllTextAsync(Path.Combine(
root, "clients", "apple", "VoiceCat.iOS", "AppModel.cs"));
Assert.DoesNotContain("new Thread(", microphone);
Assert.DoesNotContain("Thread.Sleep", microphone);
Assert.Contains("owner.Audio.RunCycle()", microphone);
Assert.Contains("while (microphoneCredit >= 960)", microphone);
Assert.Contains("deviceClockedAudio: true", model);
}
[Fact]