From de693397855dce47e02218e221852fd152d0ddc4 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 10 May 2026 20:20:27 -0400 Subject: [PATCH] Codex: Stabilize proxy E2E stream isolation. Randomize proxy E2E stream names to avoid stale shared state between runs, and make the WHIP HLS check skip the first possibly incomplete segment before requiring audio/video playback. Verified with the full srs-develop proxy script set: proxy unit coverage and all proxy E2E scripts passed. Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com> --- .../scripts/proxy-e2e-redis-test.sh | 11 ++-- .../srs-develop/scripts/proxy-e2e-srt-test.sh | 5 +- .../srs-develop/scripts/proxy-e2e-test.sh | 8 ++- .../scripts/proxy-e2e-transmux-test.sh | 5 +- .../scripts/proxy-e2e-whip-test.sh | 52 ++++++++++++++++++- 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/.openclaw/skills/srs-develop/scripts/proxy-e2e-redis-test.sh b/.openclaw/skills/srs-develop/scripts/proxy-e2e-redis-test.sh index 148a81d18..e5e54f77b 100755 --- a/.openclaw/skills/srs-develop/scripts/proxy-e2e-redis-test.sh +++ b/.openclaw/skills/srs-develop/scripts/proxy-e2e-redis-test.sh @@ -38,7 +38,12 @@ PYTHON_BIN="${PYTHON_BIN:-python3}" SOURCE_FLV="$WORKSPACE/trunk/doc/source.flv" SRS_BINARY="$WORKSPACE/trunk/objs/srs" -TEST_STREAM_URL="__defaultVhost__/live/livestream" +# Randomize per run so each invocation uses unique Redis keys and never shares +# state with sibling E2E tests or a developer's local proxy that publishes to +# "live/livestream". +STREAM_NAME="redis$(date +%s)" +STREAM_PATH="live/$STREAM_NAME" +TEST_STREAM_URL="__defaultVhost__/$STREAM_PATH" # PIDs to clean up on exit. PROXY_A_PID="" @@ -279,7 +284,7 @@ echo "SRS origin started and registered in Redis." # --- Step 6: Publish RTMP stream to proxy A --- echo "=== Step 6: Publishing RTMP stream to proxy A ===" ffmpeg -stream_loop -1 -re -i "$SOURCE_FLV" -c copy -f flv \ - "rtmp://localhost:$PROXY_A_RTMP_PORT/live/livestream" >/tmp/srs-ffmpeg-redis-e2e.log 2>&1 & + "rtmp://localhost:$PROXY_A_RTMP_PORT/$STREAM_PATH" >/tmp/srs-ffmpeg-redis-e2e.log 2>&1 & FFMPEG_PID=$! echo "FFmpeg publisher PID: $FFMPEG_PID" @@ -296,7 +301,7 @@ echo "Stream publishing through proxy A." # --- Step 7: Verify RTMP playback through proxy B --- echo "=== Step 7: Verifying RTMP playback through proxy B ===" PROBE_OUTPUT=$(ffprobe -v error -show_streams \ - "rtmp://localhost:$PROXY_B_RTMP_PORT/live/livestream" 2>&1 || true) + "rtmp://localhost:$PROXY_B_RTMP_PORT/$STREAM_PATH" 2>&1 || true) if echo "$PROBE_OUTPUT" | grep -q "codec_type=video"; then echo "PASS: Video stream detected through proxy B." diff --git a/.openclaw/skills/srs-develop/scripts/proxy-e2e-srt-test.sh b/.openclaw/skills/srs-develop/scripts/proxy-e2e-srt-test.sh index 3bd387e8a..030894b47 100755 --- a/.openclaw/skills/srs-develop/scripts/proxy-e2e-srt-test.sh +++ b/.openclaw/skills/srs-develop/scripts/proxy-e2e-srt-test.sh @@ -35,7 +35,10 @@ ORIGIN_SRT_PORT=10081 SOURCE_FLV="$WORKSPACE/trunk/doc/source.flv" SRS_BINARY="$WORKSPACE/trunk/objs/srs" -STREAM_URL="live/livestream" +# Randomize per run so each invocation starts from clean origin state (HLS +# segments, RTMP source, proxy stream registry) and never shares state with +# sibling E2E tests that publish to "live/livestream". +STREAM_URL="live/srt$(date +%s)" # SRT streamid format used by SRS: "#!::r=/,m=publish|request". # @see trunk/3rdparty/srs-docs/doc/srt.md and internal/proxy/srt.go. diff --git a/.openclaw/skills/srs-develop/scripts/proxy-e2e-test.sh b/.openclaw/skills/srs-develop/scripts/proxy-e2e-test.sh index 093a731e5..61f25608e 100755 --- a/.openclaw/skills/srs-develop/scripts/proxy-e2e-test.sh +++ b/.openclaw/skills/srs-develop/scripts/proxy-e2e-test.sh @@ -24,6 +24,10 @@ PROXY_SYSTEM_API_PORT=12025 SOURCE_FLV="$WORKSPACE/trunk/doc/source.flv" SRS_BINARY="$WORKSPACE/trunk/objs/srs" ORIGIN_CONF="$WORKSPACE/trunk/conf/origin1-for-proxy.conf" +# Randomize per run so each invocation starts from clean origin state (HLS +# segments, RTMP source, proxy stream registry) and never shares state with +# sibling E2E tests that publish to "live/livestream". +STREAM_URL="live/rtmp$(date +%s)" # PIDs to clean up on exit. PROXY_PID="" @@ -143,7 +147,7 @@ echo "SRS origin started and registered." # --- Step 5: Publish RTMP stream --- echo "=== Step 5: Publishing RTMP stream to proxy ===" ffmpeg -stream_loop -1 -re -i "$SOURCE_FLV" -c copy -f flv \ - "rtmp://localhost:$PROXY_RTMP_PORT/live/livestream" >/tmp/srs-ffmpeg-e2e.log 2>&1 & + "rtmp://localhost:$PROXY_RTMP_PORT/$STREAM_URL" >/tmp/srs-ffmpeg-e2e.log 2>&1 & FFMPEG_PID=$! echo "FFmpeg publisher PID: $FFMPEG_PID" @@ -160,7 +164,7 @@ echo "Stream publishing." # --- Step 6: Verify RTMP playback --- echo "=== Step 6: Verifying RTMP playback via proxy ===" PROBE_OUTPUT=$(ffprobe -v error -show_streams \ - "rtmp://localhost:$PROXY_RTMP_PORT/live/livestream" 2>&1 || true) + "rtmp://localhost:$PROXY_RTMP_PORT/$STREAM_URL" 2>&1 || true) if echo "$PROBE_OUTPUT" | grep -q "codec_type=video"; then echo "PASS: Video stream detected." diff --git a/.openclaw/skills/srs-develop/scripts/proxy-e2e-transmux-test.sh b/.openclaw/skills/srs-develop/scripts/proxy-e2e-transmux-test.sh index c454d0458..0f9069857 100755 --- a/.openclaw/skills/srs-develop/scripts/proxy-e2e-transmux-test.sh +++ b/.openclaw/skills/srs-develop/scripts/proxy-e2e-transmux-test.sh @@ -32,7 +32,10 @@ ORIGIN_SRT_PORT=10081 SOURCE_FLV="$WORKSPACE/trunk/doc/source.flv" SRS_BINARY="$WORKSPACE/trunk/objs/srs" -STREAM_URL="live/livestream" +# Randomize per run so each invocation starts from clean origin state (HLS +# segments, RTMP source, proxy stream registry) and never shares state with +# sibling E2E tests that publish to "live/livestream". +STREAM_URL="live/transmux$(date +%s)" # PIDs to clean up on exit. PROXY_PID="" diff --git a/.openclaw/skills/srs-develop/scripts/proxy-e2e-whip-test.sh b/.openclaw/skills/srs-develop/scripts/proxy-e2e-whip-test.sh index 882a86d43..0127c6f58 100755 --- a/.openclaw/skills/srs-develop/scripts/proxy-e2e-whip-test.sh +++ b/.openclaw/skills/srs-develop/scripts/proxy-e2e-whip-test.sh @@ -35,12 +35,16 @@ ORIGIN_SRT_PORT=10081 SOURCE_FLV="$WORKSPACE/trunk/doc/source.flv" SRS_BINARY="$WORKSPACE/trunk/objs/srs" -STREAM_URL="live/livestream" +# Randomize the stream name per run so each test starts from a clean origin +# state (HLS segments, RTMP source, proxy stream registry) and never shares +# state with sibling E2E tests that publish to "live/livestream". +STREAM_NAME="whip$(date +%s)" +STREAM_URL="live/$STREAM_NAME" # WHIP endpoint exposed by the proxy. The proxy parses ?app=&stream= via # utils.ConvertURLToStreamURL, then forwards the SDP exchange to the backend # SRS origin. @see internal/proxy/api.go and internal/proxy/rtc.go. -WHIP_PUBLISH_URL="http://localhost:$PROXY_HTTP_API_PORT/rtc/v1/whip/?app=live&stream=livestream" +WHIP_PUBLISH_URL="http://localhost:$PROXY_HTTP_API_PORT/rtc/v1/whip/?app=live&stream=$STREAM_NAME" # Make the SRS origin advertise a host candidate that loops back through the # proxy. The proxy rewrites only the port in the SDP answer (origin RTC port @@ -117,6 +121,49 @@ wait_for_hls_playlist() { exit 1 } +first_hls_segment() { + local url="$1" + + curl -fsS "$url" 2>/dev/null | awk ' + /^[[:space:]]*$/ { next } + /^#/ { next } + { print; exit } + ' +} + +wait_for_hls_to_skip_first_segment() { + local url="$1" + local deadline=60 + local first_segment current_segment output + + first_segment="$(first_hls_segment "$url")" + if [[ -z "$first_segment" ]]; then + echo "FAIL: HLS playlist has no media segment: $url" >&2 + curl -fsS "$url" 2>&1 || true + exit 1 + fi + + echo "Waiting for HLS to skip the first possibly incomplete segment (up to ${deadline}s): $first_segment" + for ((i = 1; i <= deadline; i++)); do + current_segment="$(first_hls_segment "$url")" + if [[ -n "$current_segment" && "$current_segment" != "$first_segment" ]]; then + output=$("$FFPROBE_BIN" -v error -show_streams "$url" 2>&1 || true) + if echo "$output" | grep -q "codec_type=video" && echo "$output" | grep -q "codec_type=audio"; then + echo "HLS first segment advanced and audio/video is ready: $current_segment" + return + fi + fi + sleep 1 + done + + echo "FAIL: HLS did not skip the first segment and expose audio/video in ${deadline}s." >&2 + echo "Last HLS response:" >&2 + curl -fsS "$url" 2>&1 || true + echo "Last ffprobe output:" >&2 + echo "$output" >&2 + exit 1 +} + echo "=== E2E WHIP Proxy Test ===" echo "Workspace: $WORKSPACE" echo "Stream: $STREAM_URL" @@ -285,6 +332,7 @@ probe_has_audio_video "HTTP-FLV" "http://localhost:$PROXY_HTTP_SERVER_PORT/$STRE echo "=== Step 8: Verifying HLS playback via proxy ===" HLS_URL="http://localhost:$PROXY_HTTP_SERVER_PORT/$STREAM_URL.m3u8" wait_for_hls_playlist "$HLS_URL" +wait_for_hls_to_skip_first_segment "$HLS_URL" probe_has_audio_video "HLS" "$HLS_URL" # --- Step 9: WebRTC WHEP playback (placeholder) ---