Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
fd68e23
Claude: Verify WHEP playback in the proxy E2E tests with pion-whep.
winlinvip Sep 22, 2026
abaa674
Claude: Add failing SRT acceptor tests and the interfaces they mock.
winlinvip Sep 22, 2026
e30f2d0
Claude: Inject config, listener factory and SRT options into SrsSrtAc…
winlinvip Sep 22, 2026
b4ba9b2
Claude: Test the HLS session expiry with injected dependencies.
winlinvip Sep 22, 2026
c08b46d
Claude: Refuse an HLS viewer that retries with a rejected hls_ctx.
winlinvip Sep 22, 2026
8242506
Claude: Add failing tests for the HTTP static server mounts.
winlinvip Sep 22, 2026
9af3fa6
Claude: Inject config into SrsHttpStaticServer.
winlinvip Sep 22, 2026
281fc27
HTTP: Clamp the VOD MP4 range end to the last byte of the file. v8.0.42
winlinvip Sep 22, 2026
6aad15e
Claude: Inject config into SrsVodStream.
winlinvip Sep 22, 2026
2e9d258
Log: Clear the log file descriptor when the logger reopens it. v8.0.43
winlinvip Sep 22, 2026
5a81336
Claude: Defer the fast timer coroutine and clock to assemble().
winlinvip Sep 22, 2026
a4e3a0d
Timer: Notify every subscriber when one unsubscribes during the round…
winlinvip Sep 22, 2026
b27339e
Claude: Defer the hourglass coroutine and clock to assemble().
winlinvip Sep 22, 2026
dc645bb
Claude: Defer the RTMP connection identity and wiring to assemble().
winlinvip Sep 22, 2026
e4f4c48
Claude: Defer the HTTP stream server assembly to assemble().
winlinvip Sep 22, 2026
203ea11
Claude: Defer the RTSP session identity and coroutine to assemble().
winlinvip Sep 23, 2026
9e763b8
Claude: Rebuild the RTSP track set on DESCRIBE and free the replaced …
winlinvip Sep 23, 2026
558cbb8
Claude: Lock in the subscriber SSRC that survives an RTSP republish.
winlinvip Sep 23, 2026
87659ec
Claude: Refuse an RTSP SETUP that carries no transport, instead of as…
winlinvip Sep 23, 2026
f4f981d
Claude: Put the file logger's output behind an interface, so its writ…
winlinvip Sep 23, 2026
0bce13c
Claude: Treat descriptor 0 as a log file, instead of discarding every…
winlinvip Sep 23, 2026
27a13be
Claude: Put the pithy print's stage manager, clock and config behind …
winlinvip Sep 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func VersionMinor() int {
}

func VersionRevision() int {
return 41
return 44
}

func Version() string {
Expand Down
8 changes: 4 additions & 4 deletions skills/srs-develop/references/integration-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ Run focused and component-native tests first, then run every command below seque
```bash
bash skills/srs-develop/scripts/proxy-e2e-redis-test.sh
```
6. RTMP publish with RTMP, HTTP-FLV, and HLS playback verification; WHEP remains a placeholder:
6. RTMP publish with RTMP, HTTP-FLV, HLS, and WHEP playback verification:
```bash
bash skills/srs-develop/scripts/proxy-e2e-transmux-test.sh
```
7. SRT publish with SRT, RTMP, HTTP-FLV, and HLS playback verification; WHEP remains a placeholder:
7. SRT publish with SRT, RTMP, HTTP-FLV, HLS, and WHEP playback verification:
```bash
bash skills/srs-develop/scripts/proxy-e2e-srt-test.sh
```
8. WHIP publish with RTMP, HTTP-FLV, and HLS playback verification; WHEP remains a placeholder:
8. WHIP publish with RTMP, HTTP-FLV, HLS, and WHEP playback verification:
```bash
bash skills/srs-develop/scripts/proxy-e2e-whip-test.sh
```
Expand All @@ -41,7 +41,7 @@ Run focused and component-native tests first, then run every command below seque
bash skills/srs-develop/scripts/proxy-e2e-bearer-auth-test.sh
```

The SRT test requires an FFmpeg build with libsrt. The WHIP test requires the `whip` muxer and OpenSSL. Both scripts automatically run `skills/srs-develop/scripts/setup-ffmpeg-with-whip.sh` on macOS when no suitable FFmpeg is available. If an environmental dependency is unavailable, run the script, preserve its exact result, and report the blocked coverage instead of claiming full verification.
The SRT test requires an FFmpeg build with libsrt. The WHIP test requires the `whip` muxer and OpenSSL. Both scripts automatically run `skills/srs-develop/scripts/setup-ffmpeg-with-whip.sh` on macOS when no suitable FFmpeg is available. If an environmental dependency is unavailable, run the script, preserve its exact result, and report the blocked coverage instead of claiming full verification. The transmux, SRT, and WHIP tests play WHEP with `tools/pion-whep`, because FFmpeg has no WHEP demuxer; they build it with `go` when the binary is missing or stale.

Run feature-specific bundled tests in addition to this matrix when the routed workflow or the touched area requires them:

Expand Down
64 changes: 57 additions & 7 deletions skills/srs-develop/scripts/proxy-e2e-srt-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# - RTMP play (via srt_to_rtmp on origin)
# - HTTP-FLV (HTTP remux of the bridged RTMP)
# - HLS (m3u8 + TS segments)
# - WebRTC WHEP (placeholder only, not actually verified here)
# - WebRTC WHEP (via rtmp_to_rtc on origin, played with tools/pion-whep)
set -e

SCRIPT_DIR="$(cd -P "$(dirname "$0")" && pwd)"
Expand Down Expand Up @@ -100,6 +100,50 @@ probe_has_audio_video() {
fi
}

# Play over WHEP with tools/pion-whep, because FFmpeg has no WHEP demuxer, and
# require both video and audio RTP packets. The tool is rebuilt when its binary
# is missing or older than its sources.
verify_whep_playback() {
local url="$1"
local log="$2"
local tool_dir="$WORKSPACE/tools/pion-whep"
local tool_bin="$tool_dir/objs/pion-whep"
local summary video audio

if [[ ! -x "$tool_bin" ]] || [[ -n "$(find "$tool_dir" -maxdepth 1 \( -name '*.go' -o -name 'go.mod' -o -name 'go.sum' \) -newer "$tool_bin")" ]]; then
echo "Building pion-whep: $tool_bin"
(cd "$tool_dir" && mkdir -p objs && go build -o objs/pion-whep .)
fi

echo "Verifying WHEP playback: $url"
if ! "$tool_bin" -hide_banner -f whep -i "$url" -t 5 -f null - >"$log" 2>&1; then
echo "FAIL: WHEP playback failed. pion-whep log:" >&2
cat "$log" >&2
exit 1
fi

summary="$(grep -a "^Received video=" "$log" | tail -1)"
video="$(echo "$summary" | sed -n 's/^Received video=\([0-9]*\),.*/\1/p')"
audio="$(echo "$summary" | sed -n 's/^Received video=[0-9]*, audio=\([0-9]*\) .*/\1/p')"
echo "pion-whep: $summary"

if [[ -n "$video" && "$video" -gt 0 ]]; then
echo "PASS: WHEP video packets received."
else
echo "FAIL: WHEP no video packets received." >&2
cat "$log" >&2
exit 1
fi

if [[ -n "$audio" && "$audio" -gt 0 ]]; then
echo "PASS: WHEP audio packets received."
else
echo "FAIL: WHEP no audio packets received." >&2
cat "$log" >&2
exit 1
fi
}

wait_for_hls_playlist() {
local url="$1"
local deadline=45
Expand Down Expand Up @@ -133,6 +177,10 @@ if ! command -v curl &>/dev/null; then
echo "Error: curl not found in PATH" >&2
exit 1
fi
if ! command -v go &>/dev/null; then
echo "Error: go not found in PATH" >&2
exit 1
fi

# SRT URLs need libsrt compiled into ffmpeg/ffprobe. The default Homebrew
# ffmpeg formula does NOT include libsrt. Resolution order:
Expand Down Expand Up @@ -233,7 +281,10 @@ echo "Proxy started."
echo "=== Step 4: Starting SRS origin ==="
ulimit -n 10000 2>/dev/null || true
cd "$WORKSPACE/trunk"
./objs/srs -c conf/origin1-for-proxy.conf >/tmp/srs-origin-srt-e2e.log 2>&1 &
# The proxy rewrites only the port of the WebRTC candidate, so the origin must
# advertise an IP the WHEP player can reach.
env CANDIDATE="127.0.0.1" \
./objs/srs -c conf/origin1-for-proxy.conf >/tmp/srs-origin-srt-e2e.log 2>&1 &
ORIGIN_PID=$!
echo "SRS origin PID: $ORIGIN_PID"

Expand Down Expand Up @@ -285,11 +336,10 @@ HLS_URL="http://localhost:$PROXY_HTTP_SERVER_PORT/$STREAM_URL.m3u8"
wait_for_hls_playlist "$HLS_URL"
probe_has_audio_video "HLS" "$HLS_URL"

# --- Step 10: WebRTC WHEP playback (placeholder) ---
echo "=== Step 10: WebRTC WHEP playback (placeholder) ==="
echo "SKIP: WebRTC WHEP playback is not verified by this script."
echo " The origin has rtmp_to_rtc enabled, so SRT->RTMP->RTC should work end-to-end,"
echo " but actual playback verification is intentionally left as a TODO here."
# --- Step 10: Verify WebRTC WHEP playback (srt_to_rtmp + rtmp_to_rtc) ---
echo "=== Step 10: Verifying WebRTC WHEP playback via proxy ==="
verify_whep_playback "http://localhost:$PROXY_HTTP_API_PORT/rtc/v1/whep/?app=live&stream=${STREAM_URL#live/}" \
/tmp/srs-pion-whep-srt-e2e.log

echo ""
echo "=== E2E SRT Proxy Test PASSED ==="
66 changes: 58 additions & 8 deletions skills/srs-develop/scripts/proxy-e2e-transmux-test.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/bin/bash
# E2E test for RTMP-to-multiple-protocol transmuxing through the proxy:
# starts one proxy with memory load balancer + one SRS origin, publishes one
# RTMP stream, then verifies RTMP, HTTP-FLV, and HLS playback through the
# proxy. WebRTC WHEP verification is intentionally a placeholder (not run).
# RTMP stream, then verifies RTMP, HTTP-FLV, HLS, and WebRTC WHEP playback
# through the proxy. WHEP is played with tools/pion-whep.
set -e

SCRIPT_DIR="$(cd -P "$(dirname "$0")" && pwd)"
Expand Down Expand Up @@ -92,6 +92,50 @@ probe_has_audio_video() {
fi
}

# Play over WHEP with tools/pion-whep, because FFmpeg has no WHEP demuxer, and
# require both video and audio RTP packets. The tool is rebuilt when its binary
# is missing or older than its sources.
verify_whep_playback() {
local url="$1"
local log="$2"
local tool_dir="$WORKSPACE/tools/pion-whep"
local tool_bin="$tool_dir/objs/pion-whep"
local summary video audio

if [[ ! -x "$tool_bin" ]] || [[ -n "$(find "$tool_dir" -maxdepth 1 \( -name '*.go' -o -name 'go.mod' -o -name 'go.sum' \) -newer "$tool_bin")" ]]; then
echo "Building pion-whep: $tool_bin"
(cd "$tool_dir" && mkdir -p objs && go build -o objs/pion-whep .)
fi

echo "Verifying WHEP playback: $url"
if ! "$tool_bin" -hide_banner -f whep -i "$url" -t 5 -f null - >"$log" 2>&1; then
echo "FAIL: WHEP playback failed. pion-whep log:" >&2
cat "$log" >&2
exit 1
fi

summary="$(grep -a "^Received video=" "$log" | tail -1)"
video="$(echo "$summary" | sed -n 's/^Received video=\([0-9]*\),.*/\1/p')"
audio="$(echo "$summary" | sed -n 's/^Received video=[0-9]*, audio=\([0-9]*\) .*/\1/p')"
echo "pion-whep: $summary"

if [[ -n "$video" && "$video" -gt 0 ]]; then
echo "PASS: WHEP video packets received."
else
echo "FAIL: WHEP no video packets received." >&2
cat "$log" >&2
exit 1
fi

if [[ -n "$audio" && "$audio" -gt 0 ]]; then
echo "PASS: WHEP audio packets received."
else
echo "FAIL: WHEP no audio packets received." >&2
cat "$log" >&2
exit 1
fi
}

wait_for_hls_playlist() {
local url="$1"
local deadline=45
Expand Down Expand Up @@ -133,6 +177,10 @@ if ! command -v curl &>/dev/null; then
echo "Error: curl not found in PATH" >&2
exit 1
fi
if ! command -v go &>/dev/null; then
echo "Error: go not found in PATH" >&2
exit 1
fi

# --- Step 0: Clean up stale state ---
rm -f "$WORKSPACE/trunk/objs/origin1.pid"
Expand Down Expand Up @@ -184,7 +232,10 @@ echo "Proxy started."
echo "=== Step 4: Starting SRS origin ==="
ulimit -n 10000 2>/dev/null || true
cd "$WORKSPACE/trunk"
./objs/srs -c conf/origin1-for-proxy.conf >/tmp/srs-origin-transmux-e2e.log 2>&1 &
# The proxy rewrites only the port of the WebRTC candidate, so the origin must
# advertise an IP the WHEP player can reach.
env CANDIDATE="127.0.0.1" \
./objs/srs -c conf/origin1-for-proxy.conf >/tmp/srs-origin-transmux-e2e.log 2>&1 &
ORIGIN_PID=$!
echo "SRS origin PID: $ORIGIN_PID"

Expand Down Expand Up @@ -230,11 +281,10 @@ HLS_URL="http://localhost:$PROXY_HTTP_SERVER_PORT/$STREAM_URL.m3u8"
wait_for_hls_playlist "$HLS_URL"
probe_has_audio_video "HLS" "$HLS_URL"

# --- Step 9: WebRTC WHEP playback (placeholder) ---
echo "=== Step 9: WebRTC WHEP playback (placeholder) ==="
echo "SKIP: WebRTC WHEP playback is not verified by this script."
echo " The origin has rtmp_to_rtc enabled, so RTMP->RTC should work end-to-end,"
echo " but actual playback verification is intentionally left as a TODO here."
# --- Step 9: Verify WebRTC WHEP playback (rtmp_to_rtc) ---
echo "=== Step 9: Verifying WebRTC WHEP playback via proxy ==="
verify_whep_playback "http://localhost:$PROXY_HTTP_API_PORT/rtc/v1/whep/?app=live&stream=${STREAM_URL#live/}" \
/tmp/srs-pion-whep-transmux-e2e.log

echo ""
echo "NOTE: RTSP is not tested here because the Go proxy currently has no RTSP listener."
Expand Down
59 changes: 53 additions & 6 deletions skills/srs-develop/scripts/proxy-e2e-whip-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# - RTMP play (via rtc_to_rtmp on origin)
# - HTTP-FLV (HTTP remux of the bridged RTMP)
# - HLS (m3u8 + TS segments)
# - WebRTC WHEP (placeholder only, not actually verified here)
# - WebRTC WHEP (RTC passthrough, played with tools/pion-whep)
set -e

SCRIPT_DIR="$(cd -P "$(dirname "$0")" && pwd)"
Expand Down Expand Up @@ -107,6 +107,50 @@ probe_has_audio_video() {
fi
}

# Play over WHEP with tools/pion-whep, because FFmpeg has no WHEP demuxer, and
# require both video and audio RTP packets. The tool is rebuilt when its binary
# is missing or older than its sources.
verify_whep_playback() {
local url="$1"
local log="$2"
local tool_dir="$WORKSPACE/tools/pion-whep"
local tool_bin="$tool_dir/objs/pion-whep"
local summary video audio

if [[ ! -x "$tool_bin" ]] || [[ -n "$(find "$tool_dir" -maxdepth 1 \( -name '*.go' -o -name 'go.mod' -o -name 'go.sum' \) -newer "$tool_bin")" ]]; then
echo "Building pion-whep: $tool_bin"
(cd "$tool_dir" && mkdir -p objs && go build -o objs/pion-whep .)
fi

echo "Verifying WHEP playback: $url"
if ! "$tool_bin" -hide_banner -f whep -i "$url" -t 5 -f null - >"$log" 2>&1; then
echo "FAIL: WHEP playback failed. pion-whep log:" >&2
cat "$log" >&2
exit 1
fi

summary="$(grep -a "^Received video=" "$log" | tail -1)"
video="$(echo "$summary" | sed -n 's/^Received video=\([0-9]*\),.*/\1/p')"
audio="$(echo "$summary" | sed -n 's/^Received video=[0-9]*, audio=\([0-9]*\) .*/\1/p')"
echo "pion-whep: $summary"

if [[ -n "$video" && "$video" -gt 0 ]]; then
echo "PASS: WHEP video packets received."
else
echo "FAIL: WHEP no video packets received." >&2
cat "$log" >&2
exit 1
fi

if [[ -n "$audio" && "$audio" -gt 0 ]]; then
echo "PASS: WHEP audio packets received."
else
echo "FAIL: WHEP no audio packets received." >&2
cat "$log" >&2
exit 1
fi
}

wait_for_hls_playlist() {
local url="$1"
local deadline=60
Expand Down Expand Up @@ -183,6 +227,10 @@ if ! command -v curl &>/dev/null; then
echo "Error: curl not found in PATH" >&2
exit 1
fi
if ! command -v go &>/dev/null; then
echo "Error: go not found in PATH" >&2
exit 1
fi

# WHIP needs an ffmpeg with the `whip` muxer (added in ffmpeg 7.1, requires
# --enable-openssl at build time for DTLS-SRTP). Neither vanilla brew nor the
Expand Down Expand Up @@ -340,11 +388,10 @@ 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) ---
echo "=== Step 9: WebRTC WHEP playback (placeholder) ==="
echo "SKIP: WebRTC WHEP playback is not verified by this script."
echo " The origin has rtmp_to_rtc enabled, so WHIP->RTMP->RTC should work end-to-end,"
echo " but actual playback verification is intentionally left as a TODO here."
# --- Step 9: Verify WebRTC WHEP playback (RTC passthrough) ---
echo "=== Step 9: Verifying WebRTC WHEP playback via proxy ==="
verify_whep_playback "http://localhost:$PROXY_HTTP_API_PORT/rtc/v1/whep/?app=live&stream=$STREAM_NAME" \
/tmp/srs-pion-whep-whip-e2e.log

echo ""
echo "=== E2E WHIP Proxy Test PASSED ==="
3 changes: 2 additions & 1 deletion trunk/configure
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,8 @@ if [[ $SRS_UTEST == YES ]]; then
MODULE_FILES+=("srs_utest_ai01" "srs_utest_ai02" "srs_utest_ai03" "srs_utest_ai04" "srs_utest_ai05"
"srs_utest_ai06" "srs_utest_ai07" "srs_utest_ai08" "srs_utest_ai09" "srs_utest_ai10" "srs_utest_ai11"
"srs_utest_ai12" "srs_utest_ai13" "srs_utest_ai14" "srs_utest_ai15" "srs_utest_ai16" "srs_utest_ai17"
"srs_utest_ai18" "srs_utest_ai19" "srs_utest_ai20" "srs_utest_ai24" "srs_utest_ai25" "srs_utest_ai26" "srs_utest_ai27")
"srs_utest_ai18" "srs_utest_ai19" "srs_utest_ai20" "srs_utest_ai24" "srs_utest_ai25" "srs_utest_ai26" "srs_utest_ai27"
"srs_utest_ai28" "srs_utest_ai29" "srs_utest_ai30" "srs_utest_ai31" "srs_utest_ai32")
if [[ $SRS_GB28181 == YES ]]; then
MODULE_FILES+=("srs_utest_manual_gb28181" "srs_utest_ai23")
fi
Expand Down
3 changes: 3 additions & 0 deletions trunk/doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ The changelog for SRS.
<a name="v8-changes"></a>

## SRS 8.0 Changelog
* v8.0, 2026-09-22, Timer: Notify every subscriber when one unsubscribes during the round. v8.0.44
* v8.0, 2026-09-22, Log: Clear the log file descriptor when the logger reopens it. v8.0.43
* v8.0, 2026-09-22, HTTP: Clamp the VOD MP4 range end to the last byte of the file. v8.0.42
* v8.0, 2026-09-21, Merge [#4746](https://github.com/ossrs/srs/pull/4746): WebRTC: Support RFC 4588 RTX retransmission with SSRC multiplexing, preferred by nack_prefer_rtx. v8.0.41 (#4746)
* v8.0, 2026-09-21, RTC: Reset the play track cache when the publisher republishes with new SSRCs. v8.0.40
* v8.0, 2026-09-21, RTC: Resolve the publish and play tracks once per SSRC through the fast cache. v8.0.39
Expand Down
23 changes: 23 additions & 0 deletions trunk/src/app/srs_app_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ class ISrsAppConfig : public ISrsConfig
virtual std::string get_https_stream_ssl_cert() = 0;
virtual std::string get_http_stream_dir() = 0;
virtual bool get_http_stream_crossdomain() = 0;
virtual bool get_vhost_http_enabled(std::string vhost) = 0;
virtual std::string get_vhost_http_mount(std::string vhost) = 0;
virtual std::string get_vhost_http_dir(std::string vhost) = 0;

public:
// WebRTC config
Expand All @@ -377,8 +380,21 @@ class ISrsAppConfig : public ISrsConfig
public:
// SRT config
virtual std::vector<std::string> get_srt_listens() = 0;
virtual int64_t get_srto_maxbw() = 0;
virtual int get_srto_mss() = 0;
virtual bool get_srto_tsbpdmode() = 0;
virtual int get_srto_latency() = 0;
virtual int get_srto_recv_latency() = 0;
virtual int get_srto_peer_latency() = 0;
virtual bool get_srto_tlpktdrop() = 0;
virtual srs_utime_t get_srto_conntimeout() = 0;
// Get the srt SRTO_PEERIDLETIMEO, peer idle timeout, default is 10000ms.
virtual srs_utime_t get_srto_peeridletimeout() = 0;
virtual int get_srto_sendbuf() = 0;
virtual int get_srto_recvbuf() = 0;
virtual int get_srto_payloadsize() = 0;
virtual std::string get_srto_passphrase() = 0;
virtual int get_srto_pbkeylen() = 0;

public:
// Stream caster config
Expand Down Expand Up @@ -640,6 +656,13 @@ class ISrsAppConfig : public ISrsConfig
virtual std::string get_engine_output(SrsConfDirective *conf) = 0;
virtual bool get_security_enabled(std::string vhost) = 0;
virtual SrsConfDirective *get_security_rules(std::string vhost) = 0;
// Whether write log to file, otherwise to console.
virtual bool get_log_tank_file() = 0;
// The file to write log to, empty if not configured.
virtual std::string get_log_file() = 0;
virtual std::string get_log_level() = 0;
virtual std::string get_log_level_v2() = 0;
virtual bool get_utc_time() = 0;
};

// The config service provider.
Expand Down
Loading
Loading