Fix iOS broadcast pump mapping churn
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

The screen-audio pump opened and disposed a memory mapping plus its container
lookup and path strings on every 5 ms tick - about 200 mapping pairs per
second of steady allocation that churned the GC under long calls. The producer
opens the ring with O_CREAT and never replaces it, so the pump now keeps one
mapping across ticks and rebuilds it only when the ring file disappears or a
drain fails.
This commit is contained in:
2026-09-23 21:47:42 +02:00
parent f348574bc1
commit 186fe6dbb6
2 changed files with 81 additions and 17 deletions
@@ -1,4 +1,5 @@
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace VoiceCat.Tests;
@@ -117,6 +118,25 @@ public class PublishServerScriptTests
Assert.DoesNotContain("if (OperatingSystem.IsIOSVersionAtLeast(27)) { model.ToggleScreenAudio();", settings);
}
[Fact]
public async Task IosBroadcastPumpKeepsOneRingMappingAcrossTicks()
{
string root = FindRoot();
string pump = await File.ReadAllTextAsync(Path.Combine(
root, "clients", "apple", "VoiceCat.iOS", "BroadcastAudioPump.cs"));
// A mapping pair plus its container lookup and path strings per 5 ms tick allocated
// steadily at 200 Hz and churned the GC under long calls. The pump opens one mapping on
// the ring's transitions and reuses it; the producer never replaces the ring file.
Assert.Single(Regex.Matches(pump, "MemoryMappedFile.CreateFromFile"));
Assert.Contains("private bool OpenMapping()", pump);
Assert.Contains("private void CloseMapping()", pump);
Assert.Contains("Thread.Sleep(5)", pump);
Assert.Contains("File.Exists(path)", pump);
Assert.DoesNotContain("using MemoryMappedFile", pump);
Assert.DoesNotContain("using MemoryMappedViewAccessor", pump);
}
[Fact]
public async Task IosCaptureDoesNotDependOnCoalescedManagedTimers()
{