fix: restore native FLV reconnect with curl fallback

This commit is contained in:
2026-08-12 12:14:43 +08:00
parent e6068d93e0
commit e0bd001541
5 changed files with 233 additions and 20 deletions
@@ -304,7 +304,8 @@ public sealed partial class FfmpegService : IFfmpegService
streamUrlResult.SelectedProtocol,
streamUrlResult.SelectedVideoCodec,
recoveryContext.InputOptionProfile,
recoveryVideoEncoder))
recoveryVideoEncoder,
recoveryContext.UseCurlFallback))
{
process.StartInfo.ArgumentList.Add(argument);
}
@@ -326,11 +327,13 @@ public sealed partial class FfmpegService : IFfmpegService
throw new InvalidOperationException("A running ffmpeg process already exists for the recording session.");
}
// When the stream URL is HTTP, launch curl to handle the HTTP connection and
// pipe its stdout into FFmpeg's stdin. This bypasses FFmpeg's built-in HTTP
// handler which has a hard-coded 4096-byte response header buffer that triggers
// "overlong headers" errors with CDNs that return oversized headers.
if (ShouldUseCurlPipe(streamUrlResult.SelectedUrl, streamUrlResult.SelectedProtocol))
// curl is a one-shot compatibility fallback for native FLV inputs whose response
// headers exceed FFmpeg's built-in HTTP header limit. Normal FLV and all HLS
// inputs stay on FFmpeg's native HTTP stack so native reconnect remains active.
if (ShouldUseCurlPipe(
streamUrlResult.SelectedUrl,
streamUrlResult.SelectedProtocol,
recoveryContext.UseCurlFallback))
{
var curlProcess = new Process
{
@@ -350,6 +353,14 @@ public sealed partial class FfmpegService : IFfmpegService
curlProcess.StartInfo.ArgumentList.Add(arg);
}
curlProcess.Exited += (_, _) =>
{
_logger.LogInformation(
"curl fallback connection ended for session {RecordSessionId} with exit code {ExitCode}.",
recordSession.Id,
runtime.CurlExitCode?.ToString() ?? "unknown");
};
curlProcess.ErrorDataReceived += (_, args) =>
{
if (!string.IsNullOrWhiteSpace(args.Data))
@@ -1451,7 +1462,7 @@ public sealed partial class FfmpegService : IFfmpegService
SystemLogLevel.Info,
"FFmpeg",
$"ffmpeg input profile={runtime.InputOptionProfile}.",
detail: $"stream={runtime.SelectedProtocol}:{runtime.SelectedQuality}; videoCodec={runtime.SelectedVideoCodec ?? "unknown"}; recoveryEncoder={runtime.RecoveryVideoEncoder.Kind}; recoveryDevice={runtime.RecoveryVideoEncoder.DevicePath ?? "default"}; attempt={runtime.RetryAttemptCount}; compatibilityRetry={runtime.HasRetriedWithCompatibilityProfile}; refreshRetry={runtime.HasRetriedWithRefreshedStream}; alternateProtocolRetry={runtime.HasRetriedWithAlternateProtocol}; softwareEncoderRetry={runtime.RecoveryContext.HasRetriedWithSoftwareEncoder}",
detail: $"stream={runtime.SelectedProtocol}:{runtime.SelectedQuality}; inputTransport={(runtime.RecoveryContext.UseCurlFallback ? "curl-fallback" : "native-http")}; nativeReconnect={(runtime.RecordingSettings.EnableAutoReconnect && !runtime.RecoveryContext.UseCurlFallback ? "enabled" : "disabled")}; videoCodec={runtime.SelectedVideoCodec ?? "unknown"}; recoveryEncoder={runtime.RecoveryVideoEncoder.Kind}; recoveryDevice={runtime.RecoveryVideoEncoder.DevicePath ?? "default"}; attempt={runtime.RetryAttemptCount}; compatibilityRetry={runtime.HasRetriedWithCompatibilityProfile}; refreshRetry={runtime.HasRetriedWithRefreshedStream}; alternateProtocolRetry={runtime.HasRetriedWithAlternateProtocol}; curlFallbackTried={runtime.RecoveryContext.HasTriedCurlFallback}; softwareEncoderRetry={runtime.RecoveryContext.HasRetriedWithSoftwareEncoder}",
liveRoomId: runtime.LiveRoomId,
recordSessionId: runtime.RecordSessionId,
recordTaskId: runtime.CurrentTaskId,