尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证High-performance RTP media routing server in Rust. Routes audio between WebRTC, RTP/SRTP, and file playback endpoints with codec transcoding (PCMU, G.722, Opus), DTMF detection/injection, PCAP recording, and voice activity detection. Controlled via WebSocket JSON API. Designed for telephony infrastructure and SIP integration.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
A high-performance RTP media routing server in Rust, loosely inspired by rtpengine.
rtpbridge sits between VoIP endpoints, routing audio between them with support for WebRTC, plain RTP/SRTP, codec transcoding, DTMF, recording, voice activity detection, and file playback. It is controlled via a WebSocket JSON interface where each connection maps 1:1 to a media session.查看完整 README ↗A high-performance RTP media routing server in Rust, loosely inspired by rtpengine.
rtpbridge sits between VoIP endpoints, routing audio between them with support for WebRTC, plain RTP/SRTP, codec transcoding, DTMF, recording, voice activity detection, and file playback. It is controlled via a WebSocket JSON interface where each connection maps 1:1 to a media session.
endpoint.transfer)session.bridge)session.attach), and empty session auto-destroy# Requires Rust 1.94+, libopus headers, a C compiler, make, Perl and curl
sh scripts/build-openssl.sh target/openssl
export OPENSSL_DIR="$PWD/target/openssl" OPENSSL_STATIC=1
cargo build --release
# Default: WebSocket on 127.0.0.1:9100, media on 127.0.0.1
./target/release/rtpbridge --listen 127.0.0.1:9100 --media-ip 203.0.113.5
# With config file
./target/release/rtpbridge --config rtpbridge.toml
Non-loopback control listeners require TLS and HMAC configuration. A trusted TLS proxy may use allow_plaintext_control = true on its protected upstream; unauthenticated remote control requires the separate explicit development exception allow_unauthenticated_control = true. The HMAC key authorizes all sessions.
Connect a WebSocket client and send JSON messages:
# Using websocat
websocat ws://localhost:9100
{"id":"1","method":"session.create","params":{}}
| Argument | Default | Description |
|---|---|---|
--listen | 127.0.0.1:9100 | WebSocket/HTTP control plane address(es), comma-separated |
--media-ip | 127.0.0.1 | IP for all media sockets (RTP/WebRTC) |
--config | — | Path to TOML config file |
--log-level | info | Log level (trace/debug/info/warn/error) |
listen = "127.0.0.1:9100"
media_ip = "203.0.113.5" # or "203.0.113.5, 2001:db8::5" for dual-stack
rtp_port_range = [30000, 39999]
# Optional WebRTC UDP range override (inclusive); defaults to rtp_port_range.
# webrtc_port_range = [49152, 65535]
disconnect_timeout_secs = 30
shutdown_max_wait_secs = 300
max_sessions = 10000
max_endpoints_per_session = 20
max_recordings_per_session = 100
session_idle_timeout_secs = 0 # 0 = disabled
recording_dir = "/var/lib/rtpbridge/recordings"
media_dir = "/var/lib/rtpbridge/media"
cache_dir = "/tmp/rtpbridge-cache"
cache_cleanup_interval_secs = 300
ws_ping_interval_secs = 30
log_level = "info"
# See rtpbridge.toml.example for all available options
Set [tls] to serve HTTPS/WSS on the existing listen port; rtpbridge does
not mix plaintext and TLS on that port. Set auth_hmac_secret_file to require
short-lived HMAC-SHA256 signatures for control WebSocket upgrades and sensitive
HTTP routes. /audio/<connect_token> remains a separate single-use audio
capability, so AI/media consumers do not receive the control signing key. See
the configuration guide
for the exact configuration and wire format.
All communication uses JSON over WebSocket. Each connection is bound to exactly one session.
The control API is intended for backend clients. Without HMAC, privileged requests carrying a browser Origin are rejected, and loopback clients must use a loopback IP or localhost in Host. This protects local development listeners from cross-site requests and DNS rebinding. Browser audio uses the separate /audio/<connect_token> capability.
| Method | Description |
|---|---|
session.create | Create a new session |
session.attach | Reattach to an orphaned session |
session.destroy | Destroy the current session |
session.info | Get session details |
session.list | List all sessions on the server |
server.info | Get server hostname and configured media IP |
endpoint.create_from_offer | Create endpoint from remote SDP offer (auto-detects WebRTC vs RTP) |
endpoint.create_offer | Create a new endpoint and generate SDP offer |
endpoint.accept_answer | Accept remote SDP answer |
endpoint.accept_offer | Accept remote SDP offer for an existing endpoint |
endpoint.create_with_file | Create file playback endpoint |
endpoint.create_tone | Create generated tone endpoint |
endpoint.create_websocket | Create raw PCM WebSocket audio endpoint |
endpoint.remove | Remove an endpoint |
endpoint.ice_restart | ICE restart (WebRTC only) |
endpoint.update_direction | Override or restore endpoint routing direction |
endpoint.update_remote_sdp | Update remote RTP address/SRTP state without codec changes |
endpoint.file.seek | Seek file playback position |
endpoint.file.pause | Pause file playback |
endpoint.file.resume | Resume file playback |
endpoint.dtmf.inject | Inject DTMF digit into endpoint |
endpoint.dtmf.set_sensitive | Redact DTMF logs, tag control events, and omit DTMF packets from recordings for an endpoint |
endpoint.srtp_rekey |
recording.start, recording.stop, endpoint removal, and the file-playback lifecycle events carry
media-host epoch milliseconds. These use the same host clock as PCAP packet records, so callers
can safely align explicitly injected media to a recording without comparing control-plane clocks.
endpoint.file.started is emitted only immediately before the first file RTP is routed and carries
that same epoch; ledger consumers must use it rather than endpoint creation, which can remain buffering.
pcap2audio --metadata <path> writes its earliest decodable-RTP sample-zero epoch and rendered WAV
duration as JSON for conversion services.
| Event | Description |
|---|---|
dtmf | DTMF digit detected from remote endpoint |
endpoint.state_changed | Endpoint state transition |
endpoint.ice_state_changed | WebRTC ICE state transition |
endpoint.file.started | First file RTP packet entered media routing |
endpoint.file.finished | File playback completed |
endpoint.tone.finished | Tone generation completed |
endpoint.ws.connected | WebSocket audio socket attached |
endpoint.ws.disconnected | WebSocket audio socket closed |
endpoint.ws.connect_timeout | WebSocket audio endpoint was not dialed in before timeout |
endpoint.media_timeout | No media received from remote endpoint |
endpoint.rtcp_bye | RTCP BYE received from remote endpoint |
endpoint.transferred_out | Endpoint transferred to another session |
endpoint.transferred_in | Endpoint transferred in from another session |
events.dropped | Events dropped due to client backpressure |
recording.stopped | Recording stopped externally |
session.idle_timeout | Session destroyed due to inactivity |
session.empty_timeout | Session destroyed due to zero endpoints timeout |
session.orphaned | Control connection dropped, timeout running |
stats | Periodic session statistics |
vad.speech_started | Speech detected after silence |
vad.silence | Periodic silence notification |
vad.error | VAD analysis decoder could not be created |
fax.cng_detected | Fax calling tone (CNG, 1100 Hz) detected |
See Events Reference for detailed payload schemas.
rtpbridge also serves HTTP endpoints on the same listen address(es). See Configuration — HTTP REST API for full details including status codes and pagination.
| Endpoint | Method | Description |
|---|---|---|
/health | GET | Health check — returns {"status":"ok"} |
/metrics | GET | Prometheus-format metrics |
/sessions | GET | List all active sessions |
/sessions/{id} | GET | Get session details |
/recordings | GET | List PCAP recording files |
/recordings/{path} | GET | Download a recording file |
/recordings/{path} | DELETE | Delete a recording file |
WebSocket Control (JSON)
|
+------v------+
| SessionMgr | DashMap<SessionId, Session>
+------+------+
|
+------------v------------+
| Session Task | (one tokio task per session)
| |
| +--------+ +--------+ |
| | WebRTC | | RTP/ | |
| | str0m | | SRTP | | +--------+ +----------+
| +---+----+ +---+----+ | | File | | Recording|
| | | | |Playback | | (PCAP) |
| +----+-----+ | +----+----+ +----------+
| | | |
| Routing Table | |
| (sendrecv/recvonly/ | |
| sendonly directions) | |
+-------------------------+-------+
|
+------------v------------+
| Per-Endpoint UDP |
| Sockets |
+-------------------------+
# Unit tests
cargo test
# Integration tests (serial — spawns server processes)
cargo test -- --test-threads=1
MIT
| Initiate SRTP rekey (plain RTP/SRTP only) |
endpoint.transfer | Transfer an endpoint to a different session |
session.bridge | Bidirectional audio bridge between two sessions |
recording.start | Start recording (full session or single leg) |
recording.stop | Stop recording |
vad.start | Start voice activity detection on endpoint |
vad.stop | Stop voice activity detection |
fax_detect.start | Start fax tone detection (CNG/CED) on endpoint |
fax_detect.stop | Stop fax tone detection |
stats.subscribe | Subscribe to periodic session statistics |
stats.unsubscribe | Unsubscribe from statistics |
fax.ced_detected | Fax/modem answer tone (CED, 2100 Hz) detected |
fax.error | Fax analysis decoder could not be created |