AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기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 |