Skip to content

[pull] develop from ossrs:develop#70

Open
pull[bot] wants to merge 144 commits into
timfengzi:developfrom
ossrs:develop
Open

[pull] develop from ossrs:develop#70
pull[bot] wants to merge 144 commits into
timfengzi:developfrom
ossrs:develop

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Sep 15, 2025

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

Co-authored-by: OSSRS-AI <winlinam@gmail.com>
@pull pull Bot locked and limited conversation to collaborators Sep 15, 2025
@pull pull Bot added ⤵️ pull merge-conflict Resolve conflicts manually labels Sep 15, 2025
@winlinvip winlinvip force-pushed the develop branch 2 times, most recently from 2bb0a69 to 603c831 Compare September 15, 2025 12:01
Co-authored-by: OSSRS-AI <winlinam@gmail.com>
winlinvip and others added 2 commits September 15, 2025 11:02
…v7.0.89 (#4491)

The issue occurred when srs_rtp_seq_distance(start, end) + 1 resulted in
values <= 0
due to sequence number wraparound (e.g., when end < start). This caused
assertion
failures and server crashes.

SrsRtcFrameBuilder::check_frame_complete(): Added validation to return
false
  for invalid sequence ranges instead of asserting.

However, it maybe cause converting RTC to RTMP stream failure, because
this issue
should be caused by the problem of sequence number of RTP, which means
there potentially
be stream problem in RTC stream. Even so, changing assert to warning
logs is better,
because SRS should not crash when stream is corrupt.

---------

Co-authored-by: OSSRS-AI <winlinam@gmail.com>
@winlinvip winlinvip force-pushed the develop branch 7 times, most recently from 39867dc to 4aa89d6 Compare September 17, 2025 02:10
Co-authored-by: OSSRS-AI <winlinam@gmail.com>
Co-authored-by: OSSRS-AI <winlinam@gmail.com>
Co-authored-by: OSSRS-AI <winlinam@gmail.com>
winlinvip and others added 2 commits September 19, 2025 21:50
This PR refactors the stream bridge architecture in SRS to improve code
organization, type safety, and maintainability by replacing the generic
ISrsStreamBridge interface with protocol-specific bridge classes and
target interfaces.

1. New Target Interface Architecture:

- Introduces  ISrsFrameTarget for AV frame consumers (RTMP sources)
- Introduces  ISrsRtpTarget for RTP packet consumers (RTC sources)
- Introduces ISrsSrtTarget for SRT packet consumers (SRT sources)

2. Protocol-Specific Bridge Classes:

- SrsRtmpBridge: Converts RTMP frames to RTC/RTSP protocols
-  SrsSrtBridge: Converts SRT packets to RTMP/RTC protocols
-  SrsRtcBridge: Converts RTC packets to RTMP protocol

3. Simplified Bridge Management:

- Removes the generic SrsCompositeBridge chain pattern
- Each source type now uses its appropriate bridge type directly

With this improvement, you are able to implement very complex bridge and
protocol converting, for example, you can bridge RTMP to RTC with opus
audio when you support enhanced RTMP with opus.

Another plan is to support bridging RTC to RTSP, directly without
converting RTP to media frame packet, but directly deliver RTP packet
from RTC source to RTSP source.

---------

Co-authored-by: OSSRS-AI <winlinam@gmail.com>
## steps to produce:

1. ./configure --rtsp=off
2. make

---------

Co-authored-by: winlin <winlinvip@gmail.com>
ossrs-ai and others added 30 commits November 27, 2025 19:32
…4591) (#4596)

When SRT publisher disconnects, player hangs indefinitely instead of
exiting after the configured peer_idle_timeout. This is because the
consumer wait() never checks if the publisher is still connected.

After fix, player waits for peer_idle_timeout (default 10s) then exits
gracefully when no packets arrive and publisher has disconnected.
When recording HEVC streams to MP4, DVR fails with error "doesn't
support
hvcC change" (ERROR_MP4_HVCC_CHANGE).

The root cause is in video_avc_demux(): the SrsVideoFrame object is
reused
across frames, and its initialize() method does not reset
avc_packet_type.
When a sequence header is processed, avc_packet_type is set to 0
(SrsVideoAvcFrameTraitSequenceHeader). When the next video info frame
arrives (which only appears in HEVC streams), the function returns early
without assigning video->avc_packet_type, so it retains the value 0 from
the previous sequence header frame.

When DVR processes this video info frame, it checks avc_packet_type and
incorrectly identifies it as a sequence header. Since the real HEVC
sequence
header was already recorded, DVR returns the "hvcC change" error.

The fix assigns video->avc_packet_type = packet_type before returning
early for VideoInfoFrame. After the fix, avc_packet_type is correctly
set
to the actual packet type (1 or 3 for coded frames), so DVR correctly
identifies it as NOT a sequence header.

---------

Co-authored-by: OSSRS-AI <winlinam@gmail.com>
based on @HeeJoon-Kim's patch, try to fix #4594 

Fix audio-only HLS fMP4 streams causing players to skip segments.

The bug was in segment_close() which always used video_dts_ (0 for
audio-only) to calculate the final sample duration, causing unsigned
integer overflow and corrupted m4s files.

The fix passes max(audio_dts_, video_dts_) from the controller to
segment_close(), ensuring correct duration calculation for both
audio-only and video streams.

---------

Co-authored-by: OSSRS-AI <winlinam@gmail.com>
# HLS/DASH: Fix dispose() to cleanup files after unpublish

## Summary
Fixes a bug where HLS/DASH files are not deleted after the configured
`hls_dispose`/`dash_dispose` timeout.

## Problem
When a stream is unpublished:
1. `on_unpublish()` is called and sets `enabled_ = false`
2. After the dispose timeout, `cycle()` calls `dispose()`
3. `dispose()` immediately returns due to `if (!enabled_)` check at line
2722 (HLS) and line 891 (DASH)
4. `controller_->dispose()` is never called
5. Files remain on disk indefinitely

**Observed behavior**:
- Stream stopped at 11:32:42
- `dispose()` called at 11:33:14 (after 30s timeout)
- Log shows "hls cycle to dispose hls" but no "gracefully dispose hls"
message
- Files remain on disk

## Root Cause
Commit 550760f introduced an early return in `dispose()` when
`!enabled_`, which prevents file cleanup after `on_unpublish()` has
already been called and set `enabled_` to false.

## Solution
Reorder the logic in `dispose()` to:
1. Check if dispose is enabled (hls_dispose/dash_dispose > 0) first
2. Call `on_unpublish()` only if `enabled_` is still true (prevents
duplicate calls)
3. Always call `controller_->dispose()` to cleanup files when dispose
timeout occurs

This ensures files are properly cleaned up while still preventing
duplicate `on_unpublish()` calls.

## Changes Made
- **trunk/src/app/srs_app_hls.cpp** (lines 2718-2734): Reordered
dispose() logic
- **trunk/src/app/srs_app_dash.cpp** (lines 887-902): Reordered
dispose() logic
- **trunk/doc/CHANGELOG.md**: Added v7.0.137 entry

## Testing Recommendation

To verify the fix:

1. Start RTMP stream to `/live/test`:
   ```bash
   ffmpeg -re -i test.mp4 -c copy -f flv rtmp://localhost:1935/live/test
   ```

2. Wait for HLS segments to be created:
   ```bash
   ls -la /path/to/hls/live/test/
   ```

3. Stop the stream (Ctrl+C)

4. Wait for `hls_dispose` timeout (default 120s, or 30s with your
config):
   ```bash
# Watch logs for "hls cycle to dispose hls" and "gracefully dispose hls"
   tail -f srs.log
   ```

5. Verify files are deleted:
   ```bash
   ls -la /path/to/hls/live/test/
   # Should be empty or directory removed
   ```

**Expected results**:
- Before fix: Files remain on disk
- After fix: Files are deleted, logs show "gracefully dispose hls"

## Impact
- **Risk**: Low - minimal logic change, only reordering of checks
- **Breaking changes**: None
- **Performance**: No impact
- **Compatibility**: Fixes existing bug, improves expected behavior

## Checklist
- [x] Code follows project style
- [x] Both HLS and DASH are fixed
- [x] CHANGELOG updated
- [x] Tested locally (recommended before merge)
- [x] No breaking changes

## Related Issues
- Regression introduced in: 550760f
- Related to: #865 (hls_dispose feature)

---------

Co-authored-by: Jacob Su <suzp1984@gmail.com>
Move the SRS proxy server code from the standalone repository
https://github.com/ossrs/proxy into the proxy/ directory of the
main SRS repo. Also update build instructions in origin-cluster.md.
…#4643)

- Add a comprehensive ST knowledge base document:
- openclaw/memory/srs-coroutines.md
- Add ST-focused developer skill:
- openclaw/skills/st-develop/SKILL.md
- openclaw/skills/st-develop/scripts/verify.sh
- Add KB workflow skills that support ST documentation quality and
learning:
- openclaw/skills/kb-review/SKILL.md
- openclaw/skills/srs-learn/SKILL.md
- Update openclaw/skills/srs-support/SKILL.md to use dynamic SRS_ROOT
path resolution, improving portability for KB/source
 loading.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
…and knowledge base refinements (#4651)

Rewrite srs-support SKILL.md with selective knowledge loading and structured
answering-by-topic sections. Add 15 eval test cases covering protocols, codecs,
scaling, comparisons, deployment, and access control.                       
                          
Correct latency numbers in srs-overview.md: HLS is 10-30s in practice (not  
3-5s), add concrete ranges for SRT (~500ms-1s), WebRTC (~50-400ms), and     
HTTP-FLV (~1-3s). Add VLC player-side buffering warnings throughout.        
                          
Expand knowledge base entries: Security section now covers referer, IP      
allow/deny, and HTTP callback auth (no built-in user management). HTTP Callback
corrected to v0.9. Edge Cluster clarified as viewer scaling with new version
planned. Windows section explains the ST + SRT C++ exception handling blocker. 
                          
Add SRS Community Bot section to MEMORY.md with Telegram/Discord links.     
Update AGENTS.md to answer SRS support questions directly when mentioned. 

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Reorganize the SRS (Simple Realtime Server) repository to
follow a conventional Go project structure, setting the stage for a
progressive transition from a C++ project to a Go project. The proxy,
which was once contained within its own `proxy/` subdirectory, will now
be converted into the initial Go module located at the root of the
repository, serving as a template for subsequent Go modules.

- **Go module at repo root:** `go.mod` moved to repo root, module
renamed from `proxy` to `srsx`. The repo is now a proper Go project with
`cmd/` and `internal/` at the top level.
- **Elevation of Proxy Code:** Move the proxy code from
`proxy/cmd/proxy-go/` to `cmd/proxy/`, and from `proxy/internal/` to
`internal/`. The proxy serves as the inaugural application; subsequent
modules (for instance, `cmd/origin`) will mimic this arrangement.
- **Documentation Restructured:** Transfer the documentation from
`proxy/docs/` to `docs/proxy/`, revise the main README to endorse
OpenClaw as the preferred AI tool, and update `proxy/README.md` to point
to the new documentation locations.
- **Build and config:** `Makefile` moved to root, `PROXY_STATIC_FILES`
default path corrected for the new layout, `.gitignore` consolidated.
- **Cleanup:** removed standalone `proxy/LICENSE` (repo-level license
applies), all internal imports updated to `srsx/internal/...`.
- **OpenClaw workspace:** added community bot info, git workflow
conventions, and support group behavior guidance.

This restructuring was performed by OpenClaw orchestrating Claude Code
and Codex via ACP.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Replace vendor-specific config (.augment-guidelines, .augmentignore) with
a unified approach: .claude/, .codex/, and .kiro/ directories all symlink
to the canonical persona files in openclaw/ (SOUL.md, USER.md, MEMORY.md,
IDENTITY.md, TOOLS.md, AGENTS.md).

All artificial intelligence programming entities, including Claude Code, Codex, 
and Kiro, possess commonality. the same identity, memory, and conventions 
without file duplication.

- Remove .augment-guidelines and .augmentignore (Augment AI)
- Add .claude/ with settings.local.json hook to auto-load persona files
- Add .codex/ with config.toml and CODEX.md instruction entrypoint
- Rename .agents/skills to .codex/skills
- Add .kiro/steering/ with persona symlinks
- Document ACP working directory convention in TOOLS.md
- Update openclaw/.gitignore for .pi and extensions directories

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…paths

- Rename workspace directory from openclaw/ to .openclaw/ (hidden)
- Update all symlinks in .claude/, .codex/, .kiro/ to point to ../.openclaw/
- Add memory symlinks for .claude/, .codex/, .kiro/
- Replace .codex/CODEX.md regular file with symlink to AGENTS.md
- Remove .codex/AGENTS.md symlink (replaced by CODEX.md symlink)
- Update internal paths in MEMORY.md, TOOLS.md
- Remove kb-review and srs-learn skills
- Update srs-support and st-develop skills: unified SRS_ROOT resolution, relative knowledge base paths
…rewrite AI docs. v7.0.141 (#4654)

Restructure the OpenClaw workspace so all SRS project directories are
accessible via symlinks from `.openclaw/`, eliminating the need for
parent traversal or absolute paths. All AI tools (OpenClaw, Claude Code,
Codex, Kiro) now see the same relative paths from the workspace root.

**Workspace restructuring**
- Add symlinks in `.openclaw/` for `trunk/`, `cmd/`, `internal/`,
`cmake/`, `docs/`, `objs/`, and a self-referential `.openclaw` link
- Add root-level `memory` symlink pointing to `.openclaw/memory`
- Simplify `TOOLS.md` working directory rules: everything is relative
from CWD
- Update `.gitignore` patterns for `personal*`, `support*`,
`srs-consults*` directories

**New codebase map (`memory/srs-codebase-map.md`)**
- Comprehensive map of the entire SRS codebase: C++ media server modules
(`core/`, `kernel/`, `protocol/`, `app/`), State Threads, Go next-gen
server (`cmd/` + `internal/`), documentation, and testing structure
- Enables AI to reason about which files are relevant to a question
instead of blind grepping
- Added "Codebase map first" rule to `MEMORY.md`: always load the map
before searching code

**Skill updates**
The `srs-support` has been reorganized into a three-phase workflow
consisting of Setup, Load Knowledge, and Answer by Topic. It now
features a tiered approach to knowledge integration, with the codebase
map being incorporated as the third layer.
- `st-develop`: Simplified setup, added codebase map reference
For both skills, the dynamic resolution logic for `SRS_ROOT` has been
eliminated. Now, all paths are relative.

**Documentation rewrite (`getting-started-ai.md`)**
- Replaced Augment Code / GitHub Copilot / PR review content with
current AI tooling: SRS Robot (Telegram/Discord), Claude Code, Codex,
Kiro, and OpenClaw
- Added sections on skills and the knowledge base philosophy

**Cleanup**
- Removed `docs/ideas.md`, `docs/youtube/` transcripts, and
`proxy/README.md`
- Removed "Ideas Capture" and "YouTube Channel Content" sections from
`MEMORY.md`
- Fixed origin cluster doc build command (`cd srs && make`)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…oting, and workspace updates (#4655)

Enhance the srs-support skill with doc-based knowledge layers, a full
troubleshooting section, and new eval cases. Update workspace config
files with model auth notes, voice dictation dictionary, and gitignore
patterns.

srs-support skill:
- Reframe skill scope: operators and users, not developers
- Add Layer 2 doc file mapping (25+ topic-to-doc-file entries) so the
  skill loads relevant doc files instead of jumping to source code
- Add Step 4 troubleshooting section covering WebRTC candidate issues,
  HLS latency tuning, stream-not-found diagnostics, reverse proxy
  problems, VLC buffering trap, and firewall port reference
- Add Oryx out-of-scope policy (planned but not available yet)
- Add 6 new eval cases (ids 15-20) for troubleshooting scenarios
- Fix unicode arrows in evals for cross-platform compatibility

Workspace updates:
- TOOLS.md: Add model auth refresh instructions and git commit workflow
- USER.md: Add voice dictation dictionary for speech-to-text corrections
- srs-overview.md: Replace ASCII diagram with Mermaid, expand browser
  publisher description for mobile WHIP support
- .claude/settings.local.json: Add read-only shell command permissions
- .gitignore: Add workspace pattern exclusions

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…. v7.0.142 (#4657)

Summary
- Extract proxy bootstrap implementation from bootstrap.go into
internal/bootstrap/proxy.go, keeping only the Bootstrap interface in the
shared file. This prepares for origin/edge servers
  to have their own bootstrap implementations.
- Rename NewBootstrap() → NewProxyBootstrap() to follow the explicit
factory naming convention.
- Rebrand signature from SRSProxy to SRSX and update logger context key
accordingly.
- Add srs-develop skill with task router, module routing workflow, proxy
unit test script, and RTMP E2E test script.
- Remove st-develop skill (superseded by srs-develop).
- Add srs-support eval #21 for HLS AnnexB decode error scenario.
Test plan
- go build ./cmd/proxy/... compiles successfully
  - go test ./cmd/... ./internal/... passes
- E2E RTMP proxy test (proxy-e2e-test.sh) passes
  - Verify proxy starts and logs SRSX-Proxy/<version> started

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…and update docs. v7.0.143 (#4661)

- Move build output from `./srs-proxy` to `bin/srs-proxy` following Go
project conventions, updating Makefile, .gitignore, and all
documentation references
- Replace third-party `godotenv` dependency with a custom `.env` parser
that supports comments, `export` prefix, quoted values, escape
sequences, and inline comments — with full unit tests
- Remove `ignore-worklog.md` and update `README.md` with skill-based AI
prompts
- Bump copyright year from 2025 to 2026 across all source files

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
#4665)

- **Refactor `internal/env` for testability.** Route every
`os`/filesystem
  call in `env.go` through swappable package-level function variables
(`getEnv`, `setEnv`, `lookupEnv`, `openFile`). Split `parseEnvFile` into
a
thin file-opening wrapper plus a pure `parseEnvReader(io.Reader)` so the
  parser can be tested directly without touching disk.
- **Hermetic tests, 96.9% coverage.** Rewrite `internal/env/env_test.go`
to
install in-memory fakes via `withFakeEnv` / `withFakeOpen` helpers that
  swap the package vars and restore them on `t.Cleanup`. Tests no longer
mutate real process env or write temp `.env` files, removing a source of
flakiness under parallel test execution. New cases cover
`NewEnvironment`,
`setEnvDefault`, `loadEnvFile` error paths, and edge cases in the
parser.
- **Counterfeiter-based fake generation.** Add `counterfeiter` as a Go
tool
dependency, a `//go:generate` directive for the `Environment` interface
  (`internal/env/gen.go`), and commit the generated
  `internal/env/envfakes/fake_environment.go` so downstream packages can
test against a spec-faithful fake instead of hand-rolling stubs. Expose
  the step as `make generate`.
- **Tooling.** `scripts/proxy-utest.sh` gains a `--coverage` / `-c` flag
  that runs `go test -coverprofile=...` across `./cmd/...` and
  `./internal/...` and prints per-function coverage via `go tool cover
  -func`. The `srs-develop` skill doc is updated to include the
  regenerate-fakes step and the new coverage flag.
- **Go version.** Bump `go.mod` to Go 1.25 (required for the `go tool`
  directive used to pin the counterfeiter CLI as a tool dep).

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
….145 (#4667)

Modernizes several `internal/*` packages under the Go proxy, replaces
third-party forks with standard-library primitives, and brings the
test suite from near-zero to high coverage across the touched packages.

Package changes

- **`internal/errors`** — Rewrites the `pkg/errors` fork as a thin
wrapper
  over stdlib `errors`. A single `withStack` struct captures stack
  traces via `runtime.Callers`; `fmt.Errorf("%w", ...)` handles all
  message wrapping. Restores `errors.Is`/`As`/`Unwrap` chain traversal
  (silently broken in the fork) and deletes ~190 lines of stack/frame
  formatting. `Is`, `As`, `Unwrap`, and `Join` are re-exported so
  callers need a single import.
- **`internal/logger`** — Swaps stdlib `log.Logger` for `log/slog` JSON
  handlers with UTC timestamps and custom level labels (`verb`, `debug`,
  `warn`, `error`). Hides `withContextID` (no external callers).
- **`internal/sync`** — Converts `Map[K, V]` from a concrete struct to
  an interface with a `NewMap` constructor for testability.
- **`internal/signal`** — Adds `signalNotify` / `osExit` indirections so
  `InstallSignals` and `InstallForceQuit` can be exercised without real
  OS signals or process termination.
- **`internal/utils`** — Drops deprecated `io/ioutil` and the stdlib
  `errors` alias (the internal `errors` package re-exports what's
  needed).
- **`internal/version`** — No code changes; fully covered by new tests.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This PR refines the next-generation proxy internals and workspace
documentation:

  - Reworks internal/logger to expose clearer slog-style APIs:
      - Replaces Vf/Df/Wf/Ef with Info/Debug/Warn/Error.
      - Adds structured key/value log arguments.
      - Adds version to every log record.
      - Uses standard slog level labels (DEBUG, INFO, WARN, ERROR).
      - Keeps compatibility for existing printf-style messages.
  - Renames proxy configuration abstractions:
      - Environment → ProxyEnvironment.
      - NewEnvironment → NewProxyEnvironment.
- Regenerates/renames the counterfeiter fake to FakeProxyEnvironment.
- Updates all proxy bootstrap, load balancer, protocol, signal, debug,
and utility call sites for the new logger and
    environment APIs.
  - Consolidates proxy codebase navigation:
      - Deletes docs/proxy/proxy-files.md.
- Moves the useful file/module map details into
.openclaw/memory/srs-codebase-map.md.
- Replaces agent instruction symlinks with explicit workspace
instruction files for Claude, Codex, and Kiro.
  - Updates OpenClaw tool notes with Codex commit-prefix guidance.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…4672)

This PR refactors the Go proxy server internals and significantly
expands RTMP/proxy verification coverage.

- Rename internal/protocol to internal/server to better describe the
package responsibility.
- Refactor proxy server constructors and types toward cleaner exported
interfaces:
      - NewRTMPServer
      - NewWebRTCServer
      - NewHTTPAPIServer
      - NewHTTPStreamServer
      - NewSystemAPI
  - Expose RTMP protocol interfaces for better testability:
      - Handshake
      - Protocol
      - Message
- AMF0 public interfaces such as Amf0Any, Amf0Number, Amf0String,
Amf0Object, etc.
- Add RTMP unit tests covering AMF0, handshake, protocol messages,
packet encoding/decoding, and API examples.
  - Add generated RTMP fakes for interface-based tests.
  - Add proxy E2E scripts for:
      - multi-origin memory load-balancer routing
      - Redis multi-proxy routing
- RTMP transmuxing verification across RTMP, HTTP-FLV, HLS, and optional
WebRTC WHEP
- Update OpenClaw/SRSBot development docs and memory to reflect the new
package layout, new verification scripts, and unsupported origin/edge
development scope.

---------

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
…0.148 (#4675)

- Refactor the Go proxy for dependency injection: every proxy server,
the bootstrap, the signal handler, the load balancers, and AMF0 now accept
functional-option seams (factories/closures) so tests can inject fakes
without binding real sockets, talking to real Redis, or racing on
package globals.

- Drop the package-global `lb.SrsLoadBalancer`. The bootstrap creates
the LB locally and threads it through every proxy server constructor. Two old
global indirections in `internal/signal` and `internal/rtmp/amf0` are
likewise replaced by per-instance fields.

- Rename `internal/server` → `internal/proxy` and rename the `lb` public
surface for clarity: `SRSLoadBalancer` is split into `OriginService` /
`HLSService` / `RTCService` and recomposed as `OriginLoadBalancer`;
`SRSServer` → `OriginServer`; all proxy server types gain a `Proxy`
qualifier (e.g. `RTMPServer` → `RTMPProxyServer`).

- Extract the Redis client behind a new `internal/redisclient` package
with a minimal `RedisClient` interface and a counterfeiter fake.

- Add counterfeiter fakes (`proxyfakes`, `lbfakes`, `redisclientfakes`)
and ~7.5k lines of unit tests covering bootstrap, memory + Redis LBs, all
five proxy servers, the signal handler, and AMF0.

- Add two new E2E flows — `proxy-e2e-srt-test.sh` (SRT publish through
proxy, verify SRT/RTMP/HTTP-FLV/HLS playback) and `proxy-e2e-whip-test.sh`
(WHIP publish, verify RTMP/HTTP-FLV/HLS via origin `rtc_to_rtmp`) — plus
`setup-ffmpeg-with-whip.sh`, a macOS builder for an ffmpeg with
openssl-DTLS WHIP and SRT support that the two scripts auto-invoke when needed.

- Workspace reorg: move `memory/` and `skills/` to the repo root so all
agent tools (Claude / Codex / Kiro / OpenClaw) share one source of truth via
symlinks. Sync `docs/proxy/proxy-load-balancer.md` and
`memory/srs-codebase-map.md` with the new names.

No protocol, log, HTTP API, or wire-format changes. Refactor only — all
  externally observable proxy behavior is unchanged.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
"Free" represents the new era of open source development empowered by AI. Both freedom and free — the AI agent is not just free labor, it is like a copy of myself, or even tens of copies, all deeply understanding this project, how to deliver high-quality code, and how to serve the community. AI handles all the dirty work — the boring tasks, the documentation, the coding — and often does it better than I could, with ten times the power. We built an AI robot for the community to answer questions and help users learn this project, and we used AI to almost entirely rewrite the SRS Proxy server — its structure, its workflow — so that AI agents can comprehensively manage and maintain it. With AI I have power, and I have choice: no longer waiting for other developers to contribute, I am free to manage this project, freed from the labor of maintaining it alone. This is a fantastic, amazing new era for building and sustaining open source projects and communities.
…v8.0.1 (#4676)

- Fix a goroutine leak on the WHEP path: the backend→client reader was
being spawned on every inbound client packet (STUN keepalives + RTCP
feedback), leaking tens of thousands of goroutines under steady-state
load. Now spawned exactly once per connection via `sync.Once` on both
the RTC and SRT proxies. Listener and reader receive buffers are also
reused across iterations.
- Make the legacy SRS `/rtc/v1/play/` and `/rtc/v1/publish/` APIs work
end-to-end through the proxy. Those endpoints wrap the SDP in a JSON
envelope (`{"sdp":"v=0\r\n..."}` where `\r\n` is the literal 2-byte JSON
escape, not real CRLF), so ICE parsing previously absorbed the rest of
the body into the ufrag. Added `unwrapSDPEnvelope` for ICE extraction
and tightened `ParseIceUfragPwd`'s value class to stop at `\`. The bytes
forwarded to the client and the in-body candidate-port rewrite still
operate on the raw envelope.
- Enable `net/http/pprof` endpoints when `GO_PPROF` is set (blank import
in `internal/debug/pprof.go`) and add `docs/perf/proxy-whep.md` walking
through CPU/alloc/heap/goroutine/trace collection and `pprof -base`
before/after diffs for the WHEP workload (1 publisher + N players).
- Tighten `SRTHandshakePacket.UnmarshalBinary` to
`bytes.Clone(ExtraData)` so decoded handshakes kept on the connection
(`handshake0`, `handshake2`) stay valid once the receive buffer is
reused.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…8.0.2 (#4678)

Two edge-cluster regressions surfaced when validating an RTMP
origin/edge setup. Each is a small, surgical fix in its own commit.

- **HTTP-FLV play on edge always 404'd.**
`SrsHttpStreamServer::assemble()` registered the dynamic matcher only
when the mux cast was `NULL` (inverted guard), so the matcher was never
wired up. On edge the FLV mount is created lazily by the dynamic
matcher, so every HTTP-FLV client got 404. Invert the guard to register
when the mux is valid, mirroring the destructor.
(`trunk/src/app/srs_app_http_stream.cpp`)

- **RTMP players that join an edge stream after the first player fail to
decode.** After v7.0.94 (#4513) stopped creating `SrsOriginHub` on edge,
the `hub_active` gate in `SrsLiveSource::consumer_dumps()` always
evaluated false on edge. That gate guards the dump of cached
`onMetaData` + AVC sequence header + AAC sequence header + GOP cache to
a new consumer. Result: the first player attaches before the edge-pull
starts and gets headers via the live fan-out, but every subsequent
player gets coded payload with no codec config and ffmpeg aborts with
`dimensions not set` / `Could not write header`. Fall back to the meta
cache state when `hub_` is `NULL`, so the dump path runs once the
edge-pull has populated the cache.
(`trunk/src/app/srs_app_rtmp_source.cpp`)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

⤵️ pull merge-conflict Resolve conflicts manually

Projects

None yet

Development

Successfully merging this pull request may close these issues.