Add TCP tunnel fallback for stream proof
This commit is contained in:
parent
85d021faef
commit
477d421dbf
4 changed files with 69 additions and 12 deletions
|
|
@ -97,6 +97,22 @@ powershell -ExecutionPolicy Bypass -File .\scripts\record-stream-proof-output.ps
|
|||
-MicOffsetSeconds 0.000
|
||||
```
|
||||
|
||||
If Windows firewall blocks direct SRT/UDP during a local proof, run the Raven
|
||||
leg through an SSH TCP tunnel instead:
|
||||
|
||||
```powershell
|
||||
Start-Process ssh.exe -ArgumentList '-o ExitOnForwardFailure=yes -N -L 6204:127.0.0.1:5204 -l "madman''s lullaby" 192.168.1.84' -WindowStyle Hidden
|
||||
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\record-stream-proof-output.ps1 `
|
||||
-StartRavenSender `
|
||||
-RavenSenderListens `
|
||||
-RavenSenderTransport tcp-listener `
|
||||
-RavenInputOverride tcp://127.0.0.1:6204
|
||||
```
|
||||
|
||||
That fallback keeps the proof private to the LAN/SSH path and avoids changing
|
||||
machine firewall policy just to capture a judging artifact.
|
||||
|
||||
## Scaling Rule
|
||||
|
||||
Viewer capacity is approximately:
|
||||
|
|
|
|||
|
|
@ -10,8 +10,13 @@ param(
|
|||
[string]$FfmpegPath = "ffmpeg",
|
||||
[switch]$StartRavenSender,
|
||||
[string]$RavenHost = "madman's lullaby@192.168.1.84",
|
||||
[string]$RavenAddress = "192.168.1.84",
|
||||
[string]$RavenRepo = "C:\Meta\Mimir",
|
||||
[string]$StarfireHost = "192.168.1.66",
|
||||
[switch]$RavenSenderListens,
|
||||
[ValidateSet("srt", "tcp-listener")]
|
||||
[string]$RavenSenderTransport = "srt",
|
||||
[string]$RavenInputOverride = "",
|
||||
[string]$KiyoVideoDevice = "USB Video Device",
|
||||
[string]$StarfireScarlettAudioDevice = "Analogue 1 + 2 (2- Focusrite USB Audio)",
|
||||
[int]$KiyoWidth = 640,
|
||||
|
|
@ -28,6 +33,18 @@ param(
|
|||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Quote-ProcessArgument([string]$Value) {
|
||||
if ($Value.Length -eq 0) {
|
||||
return '""'
|
||||
}
|
||||
|
||||
if ($Value -notmatch '[\s"]') {
|
||||
return $Value
|
||||
}
|
||||
|
||||
return '"' + $Value.Replace('"', '\"') + '"'
|
||||
}
|
||||
|
||||
$repo = Split-Path -Parent $PSScriptRoot
|
||||
$absoluteOutputPath = if ([System.IO.Path]::IsPathRooted($OutputPath)) {
|
||||
$OutputPath
|
||||
|
|
@ -46,13 +63,21 @@ $timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
|||
$stdoutLog = Join-Path $absoluteLogRoot "stream-proof-record-$timestamp.out.log"
|
||||
$stderrLog = Join-Path $absoluteLogRoot "stream-proof-record-$timestamp.err.log"
|
||||
|
||||
$ravenEndpoint = "srt://0.0.0.0:${RavenPort}?mode=listener&latency=120000&timeout=5000000"
|
||||
$ravenEndpoint = if ($RavenInputOverride.Length -gt 0) {
|
||||
$RavenInputOverride
|
||||
} elseif ($RavenSenderListens) {
|
||||
"srt://${RavenAddress}:${RavenPort}?mode=caller&latency=120000&timeout=30000000"
|
||||
} else {
|
||||
"srt://0.0.0.0:${RavenPort}?mode=listener&latency=120000&timeout=30000000"
|
||||
}
|
||||
$ravenSender = "${RavenRepo}\scripts\start-raven-av-sender.ps1"
|
||||
|
||||
if ($StartRavenSender) {
|
||||
$taskName = "MimirRavenAvSender$RavenPort"
|
||||
$remoteCmd = "${RavenRepo}\scripts\run-raven-av-$RavenPort.cmd"
|
||||
$remoteCommand = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File $ravenSender -TargetHost $StarfireHost -Port $RavenPort"
|
||||
$remoteTargetHost = if ($RavenSenderListens) { "0.0.0.0" } else { $StarfireHost }
|
||||
$remoteSrtMode = if ($RavenSenderListens) { "listener" } else { "caller" }
|
||||
$remoteCommand = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File $ravenSender -TargetHost $remoteTargetHost -Port $RavenPort -SrtMode $remoteSrtMode -Transport $RavenSenderTransport"
|
||||
$taskTime = (Get-Date).AddMinutes(1).ToString("HH:mm")
|
||||
Write-Host "Starting Raven muxed A/V sender on ${RavenHost} through interactive task ${taskName}: $remoteCommand"
|
||||
if (-not $DryRun) {
|
||||
|
|
@ -134,6 +159,7 @@ $arguments += @(
|
|||
|
||||
Write-Host "Stream-proof recording:"
|
||||
Write-Host " Raven input: $ravenEndpoint"
|
||||
Write-Host " Raven SRT mode: $(if ($RavenSenderListens) { 'Raven listener, Starfire caller' } else { 'Starfire listener, Raven caller' })"
|
||||
Write-Host " Kiyo PIP: $KiyoVideoDevice ${KiyoWidth}x${KiyoHeight}@$KiyoFrameRate -> ${KiyoCornerWidth}x${scaledKiyoHeight}"
|
||||
Write-Host " Raven audio: Realtek/default render loopback in muxed NVENC/SRT feed"
|
||||
Write-Host " Starfire Scarlett: $(if ($NoStarfireScarlett) { 'disabled' } else { $StarfireScarlettAudioDevice })"
|
||||
|
|
@ -153,9 +179,7 @@ $startInfo.FileName = $FfmpegPath
|
|||
$startInfo.UseShellExecute = $false
|
||||
$startInfo.RedirectStandardOutput = $true
|
||||
$startInfo.RedirectStandardError = $true
|
||||
foreach ($argument in $arguments) {
|
||||
[void]$startInfo.ArgumentList.Add($argument)
|
||||
}
|
||||
$startInfo.Arguments = ($arguments | ForEach-Object { Quote-ProcessArgument $_ }) -join " "
|
||||
|
||||
$process = [System.Diagnostics.Process]::Start($startInfo)
|
||||
if (-not $process) {
|
||||
|
|
@ -170,8 +194,8 @@ if (-not $process.WaitForExit($timeoutMs)) {
|
|||
throw "FFmpeg recorder timed out after $($DurationSeconds + $StartupTimeoutSeconds)s. Check $stderrLog."
|
||||
}
|
||||
|
||||
$stdoutTask.GetAwaiter().GetResult()
|
||||
$stderrTask.GetAwaiter().GetResult()
|
||||
[void]$stdoutTask.GetAwaiter().GetResult()
|
||||
[void]$stderrTask.GetAwaiter().GetResult()
|
||||
if ($process.ExitCode -ne 0) {
|
||||
throw "FFmpeg recorder failed with exit code $($process.ExitCode). Check $stderrLog."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ param(
|
|||
[int]$Framerate = 30,
|
||||
[int]$AudioSampleRate = 48000,
|
||||
[int]$AudioChannels = 2,
|
||||
[ValidateSet("srt", "tcp-listener")]
|
||||
[string]$Transport = "srt",
|
||||
[ValidateSet("caller", "listener")]
|
||||
[string]$SrtMode = "caller",
|
||||
[string]$FfmpegPath = "ffmpeg",
|
||||
[string]$Source = "desktop",
|
||||
[string]$VideoBitrate = "12000k",
|
||||
|
|
@ -25,7 +29,11 @@ $repo = Split-Path -Parent $PSScriptRoot
|
|||
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
||||
$stdoutLog = Join-Path $LogRoot "raven-av-srt-$timestamp.out.log"
|
||||
$stderrLog = Join-Path $LogRoot "raven-av-srt-$timestamp.err.log"
|
||||
$endpoint = "srt://${TargetHost}:${Port}?mode=caller&latency=120000"
|
||||
$endpoint = if ($Transport -eq "tcp-listener") {
|
||||
"tcp://${TargetHost}:${Port}?listen=1"
|
||||
} else {
|
||||
"srt://${TargetHost}:${Port}?mode=${SrtMode}&latency=120000&timeout=30000000"
|
||||
}
|
||||
$videoSize = "${Width}x${Height}"
|
||||
$gop = [Math]::Max(1, $Framerate * 2)
|
||||
$captureScript = Join-Path $repo "scripts\wasapi-loopback-capture.ps1"
|
||||
|
|
@ -61,8 +69,11 @@ $ffmpegArgs = @(
|
|||
$endpoint
|
||||
)
|
||||
$quotedFfmpegArgs = $ffmpegArgs | ForEach-Object { Quote-CmdArgument $_ }
|
||||
$command = (Quote-CmdArgument $captureScript) +
|
||||
" -Output - -SampleRate $AudioSampleRate -Channels $AudioChannels | " +
|
||||
$command = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File " +
|
||||
(Quote-CmdArgument $captureScript) +
|
||||
" -Output " +
|
||||
(Quote-CmdArgument "stdout") +
|
||||
" -SampleRate $AudioSampleRate -Channels $AudioChannels | " +
|
||||
(Quote-CmdArgument $FfmpegPath) +
|
||||
" " +
|
||||
($quotedFfmpegArgs -join " ")
|
||||
|
|
@ -70,6 +81,7 @@ $command = (Quote-CmdArgument $captureScript) +
|
|||
Write-Host "Raven muxed A/V sender:"
|
||||
Write-Host " ffmpeg: $FfmpegPath"
|
||||
Write-Host " target: $endpoint"
|
||||
Write-Host " transport: $Transport"
|
||||
Write-Host " video: $Source $videoSize@$Framerate via h264_nvenc"
|
||||
Write-Host " audio: Raven Realtek/default render loopback ${AudioChannels}ch ${AudioSampleRate}Hz -> AAC"
|
||||
Write-Host " sync role: Raven Realtek is co-streamer game/program loopback packaged with NVENC; Starfire Realtek owns chirp emission"
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ namespace Mimir {
|
|||
}
|
||||
|
||||
public static void Capture(string outputPath, double seconds, int targetRate, int targetChannels, string roleName) {
|
||||
Stream output = outputPath == "-" ? Console.OpenStandardOutput() : new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
Stream output = IsStdoutPath(outputPath) ? Console.OpenStandardOutput() : new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
try {
|
||||
IMMDeviceEnumerator enumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
|
||||
IMMDevice device;
|
||||
|
|
@ -216,10 +216,15 @@ namespace Mimir {
|
|||
}
|
||||
}
|
||||
finally {
|
||||
if (outputPath != "-") output.Dispose();
|
||||
if (!IsStdoutPath(outputPath)) output.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsStdoutPath(string outputPath) {
|
||||
return String.Equals(outputPath, "-", StringComparison.Ordinal) ||
|
||||
String.Equals(outputPath, "stdout", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
static void Check(int hr, string stage) {
|
||||
if (hr < 0) {
|
||||
Exception inner = Marshal.GetExceptionForHR(hr);
|
||||
|
|
|
|||
Loading…
Reference in a new issue