fix(stepdown): restart the audio pipe around encoder changes
A quality step-down now closes the named audio pipe before stopping/flushing the pump, then opens a fresh server before restarting the pump. This prevents ffmpeg from waiting on the old audio input and avoids reconnecting to a broken pipe. EncoderRestartTests pins the audio-stop → video-stop → audio-start → video-start order. 616 tests green, clean build with 0 warnings.
This commit is contained in:
@@ -26,6 +26,7 @@ public sealed class EncoderRestartTests
|
||||
var tier = (Width: 1920, Height: 1080, Fps: 60, Bitrate: 8.0);
|
||||
var started = new List<EncoderOptions>();
|
||||
var frames = new List<CapturingEncoder>();
|
||||
var order = new List<string>();
|
||||
|
||||
var scene = new Scene { Name = "Live" };
|
||||
scene.Elements.Add(new Source { Name = "Background", Type = SourceType.Background, IsBackground = true });
|
||||
@@ -49,7 +50,12 @@ public sealed class EncoderRestartTests
|
||||
encoderFactory: () =>
|
||||
{
|
||||
var encoder = new CapturingEncoder();
|
||||
encoder.Started += options => started.Add(options);
|
||||
encoder.Started += options =>
|
||||
{
|
||||
started.Add(options);
|
||||
order.Add($"encoder-start-{options.Fps}");
|
||||
};
|
||||
encoder.Stopped = () => order.Add("encoder-stop");
|
||||
frames.Add(encoder);
|
||||
return encoder;
|
||||
},
|
||||
@@ -63,7 +69,9 @@ public sealed class EncoderRestartTests
|
||||
// options func now reports the new tier — which the restart must re-read.
|
||||
tier = (1920, 1080, 30, 6.4);
|
||||
|
||||
Assert.True(await pump.ChangeEncoderAsync());
|
||||
Assert.True(await pump.ChangeEncoderAsync(
|
||||
stopAudio: () => order.Add("audio-stop"),
|
||||
startAudio: () => order.Add("audio-start")));
|
||||
Assert.True(await frames[1].FirstFrame.Task.WaitAsync(TimeSpan.FromSeconds(5)), "restarted session never produced a frame");
|
||||
|
||||
Assert.Equal(2, started.Count);
|
||||
@@ -71,6 +79,7 @@ public sealed class EncoderRestartTests
|
||||
Assert.Equal(30, started[1].Fps);
|
||||
Assert.Equal(6400, started[1].BitrateKbps);
|
||||
Assert.NotSame(frames[0], frames[1]);
|
||||
Assert.Equal(new[] { "encoder-start-60", "audio-stop", "encoder-stop", "audio-start", "encoder-start-30" }, order);
|
||||
|
||||
await pump.StopAsync();
|
||||
}
|
||||
@@ -79,6 +88,7 @@ public sealed class EncoderRestartTests
|
||||
{
|
||||
public readonly TaskCompletionSource<bool> FirstFrame = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
public event Action<EncoderOptions>? Started;
|
||||
public Action? Stopped { get; set; }
|
||||
|
||||
public int DroppedFrames => 0;
|
||||
|
||||
@@ -97,7 +107,11 @@ public sealed class EncoderRestartTests
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
||||
public Task StopAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
Stopped?.Invoke();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user