A production-ready SIP proxy/registrar with Rust backend, Vue 3 admin UI, and WebRTC browser gateway.
SIP3 is a full-featured SIP proxy/registrar server built with:
- Backend: Rust (Tokio async, Axum REST API, SQLx + MySQL)
- Frontend: Vue 3 + Element Plus admin dashboard (Chinese/English)
- Protocols: SIP/2.0 over UDP, TCP/TLS, WebSocket, WebSocket-Secure
- WebRTC: Built-in media gateway + coturn TURN server for browser clients
- Deployment: Docker + Docker Compose
- ✅ SIP REGISTER — RFC 3261 MD5 Digest Authentication
- ✅ SIP INVITE proxy/B2BUA — looks up registration, rewrites SDP, relays RTP
- ✅ Audio conference rooms — local B2BUA endpoint with server-side mixer supporting G.711 PCMU/PCMA, G.722 wideband (16 kHz) and Opus (48 kHz mono). Per-participant sample-rate mixing (8/16/48 kHz). Dial e.g.
sip:900000000@<domain>;*6DTMF (RFC 2833 or SIP INFO) toggles mute. SIP UDP/TLS only — no SRTP/video/WebRTC, no PIN. - ✅ Voicemail — mailbox recording for offline users and unanswered calls (default 25 s), basic
*97mailbox access, and MWI viaSUBSCRIBE Event: message-summary. Accepts G.711 PCMU/PCMA, G.722 and Opus (mono) on RTP/AVP; recordings are stored as a 16 kHz canonical WAV regardless of negotiated codec. Full playback IVR/navigation, PIN, busy-to-voicemail, email notifications, SRTP, and browser/WebRTC voicemail are future work. See docs/conference-codecs.md. - ✅ SIP BYE / CANCEL / INFO bidirectional routing
- ✅ SIP REFER + NOTIFY — blind call transfer
- ✅ SIP SUBSCRIBE / NOTIFY — Presence & BLF (busy lamp field)
- ✅ SIP MESSAGE — instant messaging relay + persistence
- ✅ SIP OPTIONS — keep-alive / capability probe (inline 200 OK)
- ✅ SIP/UDP — port 5060 (default)
- ✅ SIP/TLS — port 5061 (native-tls, OS cert chain)
- ✅ SIP/WS — port 5080 (WebSocket, for browser SIP clients)
- ✅ SIP/WSS — port 5443 (WebSocket Secure, reuses TLS cert)
- ✅ Server-side RTP relay — NAT traversal for SIP phone audio and video without client STUN/TURN
- ✅ SRTP transparent relay — SDES/SAVP audio/video passthrough (end-to-end encryption)
- ✅ WebRTC media gateway — bridges browser ICE/DTLS-SRTP ↔ plain SIP phone RTP
- ✅ TURN credentials API — coturn HMAC-SHA1 time-limited credentials
- ✅ IP ACL — CIDR allow/deny rules with priority, hot-reloaded every 60 s
- ✅ JWT admin authentication (login, change-password, admin user management)
- ✅ Call Detail Records (CDR) — start/end time, duration, status
- ✅ Dashboard statistics — active registrations, ongoing calls, CDR totals
- ✅ REST API — full CRUD for accounts, registrations, ACL rules, call records
- ✅ Vue 3 + Element Plus admin dashboard (全中文界面)
- ✅ Browser softphone at
/phone— SIP.js + WebRTC audio/video, supports browser↔Linphone video interop, TURN auto-configured - ✅ Search, pagination, de-register, call statistics
- ✅ Added
/phonevideo calling with pre-call media selection, browser↔Linphone video interop, and negotiated video fallback-to-audio handling. - ✅ Added dual CI publishing topology: GitHub Actions -> GHCR and GitLab CI -> Harbor for domestic build/publish paths.
- ✅ Updated production deployment model to Harbor-only pulls with explicit source-path verification and rollback-by-tag flow.
- ✅ Fixed admin sidebar footer to render version text from frontend package metadata instead of a hardcoded value.
- ✅ Hardened GitLab Harbor publishing safety by restricting publish job execution to
mainand tags.
git clone https://github.com/wendal/sip3.git
cd sip3
cp .env.example .env
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --buildOpen http://localhost:8030 for the admin UI (default: admin / admin123).
| Service | Port(s) |
|---|---|
| Admin UI | TCP 8030 |
| REST API | TCP 3000 |
| SIP/UDP | UDP 5060 |
| SIP/TLS | TCP 5061 |
| SIP/WS | TCP 5080 |
| SIP/WSS | TCP 5443 |
| RTP relay | UDP 10000–10099 |
| Conference RTP | UDP 10100–10199 |
| Voicemail RTP | UDP 10200–10299 |
| TURN/UDP | UDP 3478 |
| TURN/TLS | TCP 5349 |
Browser (SIP.js)──WSS 5443──┐
SIP Phone ────────UDP 5060──┼──► SIP Handler (Rust)
SIP Phone (TLS) ──TLS 5061──┘ │
┌────▼────┐ ┌─────────────────┐
│ Registrar│ │ WebRTC Gateway │
│ Proxy │ │ (webrtc-rs B2BUA│
│ Presence│ │ ICE+DTLS-SRTP) │
└────┬────┘ └─────────────────┘
│
┌─────────▼─────────┐
│ MySQL 8.0 │
│ sip_accounts │
│ sip_registrations │
│ sip_calls │
│ sip_acl │
└─────────┬──────────┘
│
Admin UI ──HTTP 8030──► Nginx ─────────► REST API :3000
Public (no auth required)
| Method | Path | Description |
|---|---|---|
| GET | /api/health | Health check |
| POST | /api/auth/login | Admin login → JWT |
| POST | /api/turn/credentials | TURN creds (SIP HA1 auth) |
| POST | /api/messages/history | Phone message history (SIP credential auth) |
Protected (JWT required)
| Method | Path | Description |
|---|---|---|
| GET | /api/accounts | List SIP accounts |
| POST | /api/accounts | Create SIP account |
| PUT | /api/accounts/:id | Update SIP account |
| DELETE | /api/accounts/:id | Delete SIP account |
| GET | /api/registrations | List active registrations |
| DELETE | /api/registrations/:id | Force de-register |
| GET | /api/calls | List call records (CDR) |
| POST | /api/calls/cleanup | Close stale active calls (?older_than_hours=N, default 4; pass 0 for all). Backend also runs this automatically at startup and every 5 min. |
| GET | /api/messages | List persisted SIP MESSAGE records |
| GET/POST | /api/conferences | List/create conference rooms |
| PUT/DELETE | /api/conferences/:id | Update/delete a conference room |
| GET | /api/conferences/:id/participants | List active conference participants |
| GET/POST | /api/voicemail/boxes | List/create voicemail mailboxes |
| PUT | /api/voicemail/boxes/:id | Update voicemail mailbox settings |
| GET | /api/voicemail/messages | List voicemail messages |
| PUT/DELETE | /api/voicemail/messages/:id | Update or soft-delete a message |
| GET | /api/voicemail/messages/:id/download | Download message WAV audio |
| GET | /api/stats | Dashboard statistics |
| GET | /api/security/summary | Security summary (24h auth + INVITE abuse) |
| GET | /api/security/events | Security event timeline / filterable by surface |
| GET | /api/security/blocks | Active auto-ban ACL entries |
| POST | /api/security/blocks/unblock | Disable one auto-ban entry |
| GET | /api/security/runtime | Runtime troubleshooting snapshot |
| GET | /api/acl | List IP ACL rules |
| POST | /api/acl | Create ACL rule |
| PUT | /api/acl/:id | Update ACL rule |
| DELETE | /api/acl/:id | Delete ACL rule |
| GET | /api/auth/me | Current admin user info |
| POST | /api/auth/change-password | Change admin password |
- Delivery: if an enabled mailbox's owner is offline, SIP3 answers immediately and records a message. If the owner is registered but does not answer, SIP3 sends the call to voicemail after
SIP3__SERVER__VOICEMAIL_NO_ANSWER_SECS(default 25 seconds). - Mailbox access: users dial
*97from their own SIP account to reach the mailbox endpoint and greeting/ready prompt. Full message playback and mailbox navigation are future work. - Codecs: voicemail accepts G.711 PCMU/PCMA, G.722 wideband and Opus (RFC 7587 mono) on RTP/AVP. Recordings are stored as 16 kHz canonical WAV and resampled to the receiver's rate on playback. SRTP/SAVP, video, and browser/WebRTC voicemail are not supported.
- MWI: SIP phones can subscribe with
SUBSCRIBE Event: message-summary; SIP3 sendsNOTIFYupdates with new/saved message counts. - Storage: recordings are WAV files under
SIP3__SERVER__VOICEMAIL_STORAGE_DIR(Docker default/app/voicemail, host mount./voicemail). Prompt WAV files are read fromSIP3__SERVER__VOICEMAIL_PROMPT_DIR(defaultvoicemail/prompts). - RTP ports: voicemail media uses UDP
10200-10299by default (SIP3__SERVER__VOICEMAIL_RTP_PORT_MIN/MAX). Open and Docker-map this range separately from call relay and conference RTP. - DTMF controls: current MVP DTMF support is limited to
#stopping an active recording. Playback menu controls such as1replay,2/#next,7delete,9save, and*back/exit are planned but not implemented yet. - MVP exclusions: full message playback IVR/navigation/save/delete, mailbox PINs, busy-to-voicemail routing, email notifications, SRTP, and browser/WebRTC voicemail.
| Environment Variable | Default | Description |
|---|---|---|
| SIP3__SERVER__SIP_HOST | 0.0.0.0 | SIP bind address |
| SIP3__SERVER__SIP_PORT | 5060 | SIP UDP port |
| SIP3__SERVER__SIP_DOMAIN | sip.air32.cn | SIP domain / registrar realm |
| SIP3__SERVER__PUBLIC_IP | 154.8.159.79 | Public IPv4 written into SDP c= lines |
| SIP3__SERVER__RTP_PORT_MIN | 10000 | RTP relay port range start |
| SIP3__SERVER__RTP_PORT_MAX | 10099 | RTP relay port range end |
| SIP3__SERVER__CONFERENCE_RTP_PORT_MIN | 10100 | Conference RTP port range start |
| SIP3__SERVER__CONFERENCE_RTP_PORT_MAX | 10199 | Conference RTP port range end |
| SIP3__SERVER__VOICEMAIL_ACCESS_EXTENSION | *97 | Voicemail mailbox access extension |
| SIP3__SERVER__VOICEMAIL_NO_ANSWER_SECS | 25 | Seconds before no-answer voicemail |
| SIP3__SERVER__VOICEMAIL_MAX_MESSAGE_SECS | 120 | Maximum voicemail recording length |
| SIP3__SERVER__VOICEMAIL_IDLE_TIMEOUT_SECS | 10 | Stop recording after RTP silence |
| SIP3__SERVER__VOICEMAIL_STORAGE_DIR | voicemail | Directory for voicemail WAV files |
| SIP3__SERVER__VOICEMAIL_PROMPT_DIR | voicemail/prompts | Directory for voicemail prompt WAVs |
| SIP3__SERVER__VOICEMAIL_RTP_PORT_MIN | 10200 | Voicemail RTP port range start |
| SIP3__SERVER__VOICEMAIL_RTP_PORT_MAX | 10299 | Voicemail RTP port range end |
| SIP3__SERVER__TLS_CERT | (empty) | Path to TLS cert (PEM fullchain) |
| SIP3__SERVER__TLS_KEY | (empty) | Path to TLS private key (PEM) |
| SIP3__SERVER__WS_PORT | 5080 | SIP/WS port (0 = disabled) |
| SIP3__SERVER__WSS_PORT | 5443 | SIP/WSS port (0 = disabled) |
| SIP3__SERVER__WEBRTC_PORT_MIN | 20000 | WebRTC ICE port range start |
| SIP3__SERVER__WEBRTC_PORT_MAX | 20099 | WebRTC ICE port range end |
| SIP3__DATABASE__URL | mysql://... | MySQL connection URL |
| SIP3__AUTH__REALM | sip.air32.cn | Digest auth realm |
| SIP3__AUTH__REGISTRATION_EXPIRES | 3600 | Default registration TTL (seconds) |
| SIP3__SECURITY__WINDOW_SECS | 300 | Sliding window for auth-fail counters |
| SIP3__SECURITY__SIP_IP_FAIL_THRESHOLD | 20 | REGISTER failures/IP before block |
| SIP3__SECURITY__SIP_USER_IP_FAIL_THRESHOLD | 8 | REGISTER failures/IP+user before block |
| SIP3__SECURITY__SIP_INVITE_IP_FAIL_THRESHOLD | 10 | Rejected INVITEs/IP before block |
| SIP3__SECURITY__SIP_INVITE_USER_IP_FAIL_THRESHOLD | 3 | Rejected INVITEs/IP+caller before block |
| SIP3__SECURITY__API_IP_FAIL_THRESHOLD | 20 | Admin login failures/IP before block |
| SIP3__SECURITY__API_USER_IP_FAIL_THRESHOLD | 8 | Admin login failures/IP+user before block |
| SIP3__SECURITY__BLOCK_SECS | 900 | Auto-ban duration (seconds) |
| SIP3__SECURITY__PERSIST_ACL_BANS | true | Persist auto-ban into sip_acl |
| SIP3__SECURITY__ACL_BAN_PRIORITY | 5 | Priority for auto-ban ACL rules |
| SIP3__TURN__REALM | sip.air32.cn | TURN realm |
| SIP3__TURN__SECRET | (empty) | TURN HMAC-SHA1 shared secret |
| SIP3__TURN__TTL_SECONDS | 86400 | TURN credential lifetime (seconds) |
| SIP3__TURN__SERVER | (empty) | TURN server URI (returned to client) |
Important: set
SIP3__SERVER__PUBLIC_IPto a numeric public IPv4 (for example154.8.159.79) to avoid SIP endpoint compatibility issues caused by domain names inside SDPc=IN IP4.
For public-facing SIP servers without trusted inbound trunks, keep the new INVITE thresholds enabled so repeated INVITE from unrecognised caller scans are auto-banned and show up as surface=sip_invite / event_type=invite_rejected in /api/security/events.
# Local CI parity check (recommended before push)
pwsh ./scripts/local-ci.ps1
# Local Docker stack with source builds
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
# Backend (Rust)
cd backend
cargo fmt --check
cargo build
cargo test
cargo clippy -- -D warnings
# Frontend (Vue 3)
cd frontend
npm install
npm run dev # dev server on :5173Run the fixed TLS regression scenarios against a reachable SIP3 deployment:
cd backend
cargo run --bin headless_call_tester -- `
--target sip.air32.cn `
--tls-port 5061 `
--domain sip.air32.cn `
--realm sip.air32.cn `
--scenario tls_basic_call `
--caller 1001 `
--caller-password <password> `
--callee 1003 `
--callee-password <password> `
--rtp-threshold 8 `
--insecure-tlsSupported scenarios:
tls_register_dual- both TLS endpoints authenticate and register successfullytls_message_dual- both endpoints exchange SIP MESSAGE successfully over TLStls_basic_call- both endpoints complete a TLS call and the tester requires SIP3 to rewrite both SDP legs to relay targets before counting bidirectional RTP packetsconference_g722- caller places an INVITE to a 9-digit conference room using G.722 wideband SDP and the server's 200 OK echoesa=rtpmap:<pt> G722/8000conference_opus- same, but with Opus (RFC 7587 mono) SDP and assertsa=rtpmap:<pt> opus/48000/2+stereo=0fmtpvoicemail_g722- same asconference_g722but the target is*97(voicemail access)voicemail_opus- same asconference_opusbut the target is*97
The tester exits non-zero on scenario failure and now surfaces explicit SIP failures such as 403, 407, 486, and 5xx instead of timing out generically.
- No ringing / MESSAGE not delivered: check
sip_registrations.source_ip/source_portagainst the sender's real source socket. - Call connected but no audio: verify UDP RTP range (
10000-10099) is open and relay ports in SDP match packet source ports. - Linphone video does not appear: verify both offer and answer SDP rewrite
m=videoto the SIP3 public IP and a relay port. A SIP audio+video call consumes four RTP relay ports, so the default range supports fewer concurrent video calls than audio-only calls. Browser WebRTC video is not covered by the legacy SIP RTP relay path. - Browser↔Linphone video has no picture: confirm Linphone video is enabled, camera permission is granted on the browser, and WSS/TURN are reachable. Also verify SIP 200 OK/INVITE SDP carries active
m=video(notm=video 0) and that RTP relay ports are reachable. - Conference has no audio / cannot join: confirm the room is enabled, the phone offers RTP/AVP PCMU/PCMA, G.722 or mono Opus, and UDP
10100-10199is open. The codec selected by the server can be observed viasip3_conference_codec_total{codec="..."}on/api/metrics. - Voicemail does not answer / MWI not updated: confirm the mailbox is enabled, the caller/subscriber source matches an active registration, UDP
10200-10299is open, and prompt/storage directories are writable. - MESSAGE persistence errors (1146): ensure migration
010_sip_messages.sqlhas been applied. - GitLab CI Harbor publish fails: for the current self-hosted
linuxshell runner, ensure GitLab CI/CD variablesHARBOR_USERandHARBOR_PASSWORDare set,gitlab-runnercan access the host Docker daemon, and avoid BuildKit-only Dockerfile syntax unless the runner host is intentionally managed arounddocker buildx.
See docs/deployment.md for full deployment and TLS setup guide.
SIP3 是一个功能完整的 SIP 代理/注册服务器,使用 Rust 构建后端,Vue 3 构建管理界面,支持 WebRTC 浏览器网关和 TURN 服务。
- ✅ SIP REGISTER — RFC 3261 MD5 摘要认证
- ✅ SIP INVITE 代理/B2BUA — 查找注册、重写 SDP、中继 RTP
- ✅ 音频会议室 — 本地 B2BUA 端点,服务端混音支持 G.711 PCMU/PCMA、G.722 宽带(16 kHz)和 Opus(48 kHz 单声道)。每个参会者按自身协商采样率独立解码,混音器自动选择最高参与率合成,再降采样到接收方采样率。拨打如
sip:900000000@<域>入会;*6DTMF(RFC 2833 或 SIP INFO)切换静音。仅支持 SIP UDP/TLS,不支持 SRTP/视频/WebRTC,无 PIN。 - ✅ 语音信箱 — 离线用户和无人接听(默认 25 秒)转入本地录音;用户拨打
*97可进入基础信箱端点/问候提示;支持SUBSCRIBE Event: message-summary消息等待指示(MWI)。RTP/AVP 接收 G.711 PCMU/PCMA、G.722 和 Opus(RFC 7587 单声道);录音统一以 16 kHz canonical WAV 存储,播放时按协商采样率重采样。完整播放 IVR/导航、PIN、忙线转信箱、邮件通知、SRTP 或浏览器/WebRTC 语音信箱均为后续工作。详见 docs/conference-codecs.md。 - ✅ SIP BYE / CANCEL / INFO 双向路由
- ✅ SIP REFER + NOTIFY — 盲转呼叫
- ✅ SIP SUBSCRIBE / NOTIFY — 在线状态与 BLF(忙灯显示)
- ✅ SIP MESSAGE — 即时消息转发与持久化
- ✅ SIP OPTIONS — 保活/能力探测
- ✅ SIP/UDP — 5060 端口
- ✅ SIP/TLS — 5061 端口(系统证书链)
- ✅ SIP/WS — 5080 端口(WebSocket,供浏览器 SIP 客户端使用)
- ✅ SIP/WSS — 5443 端口(WebSocket + TLS)
- ✅ 服务端 RTP 中继 — SIP 电话音频和视频 NAT 穿透,客户端无需 STUN/TURN
- ✅ SRTP 透明中继 — SDES/SAVP 音视频直通,端到端加密
- ✅ WebRTC 媒体网关 — 浏览器 ICE/DTLS-SRTP ↔ 传统 SIP 电话 RTP 互通
- ✅ TURN 凭证 API — coturn HMAC-SHA1 时效凭证,浏览器端自动获取
- ✅ IP ACL — CIDR 允许/拒绝规则,优先级,每 60 秒热重载
- ✅ JWT 管理员认证(登录、改密、管理员用户管理)
- ✅ 通话详细记录(CDR)— 开始/结束时间、时长、状态
- ✅ 仪表盘统计 — 活跃注册数、进行中通话数、CDR 汇总
- ✅ REST API — 账户、注册、ACL、通话记录完整 CRUD
- ✅ Vue 3 + Element Plus 全中文管理界面
- ✅
/phone浏览器软电话 — SIP.js + WebRTC,支持语音与浏览器↔Linphone 视频通话,并自动获取 TURN 凭证 - ✅ 搜索、分页、强制注销、通话统计
- ✅ 新增兼容 Linphone 的 音频会议室:服务端 G.711 混音,
*6静音切换。 - ✅ 新增 语音信箱 MVP:离线/无人接听录音、WAV 存储、MWI、
*97访问准备和管理界面。 - ✅ 新增独立媒体端口范围:通话中继
10000-10099、会议10100-10199、语音信箱10200-10299、WebRTC20000-20099。 - ✅ 加固语音信箱存储键、MWI 来源校验、无人接听/CANCEL 竞态和最大留言时长校验。
- ✅ 新增 docs/architecture.md 项目架构文档。
git clone https://github.com/wendal/sip3.git
cd sip3
docker compose up -d访问 http://localhost:8030 打开管理界面(默认账户:admin / admin123)。
| 服务 | 端口 |
|---|---|
| 管理界面 | TCP 8030 |
| REST API | TCP 3000 |
| SIP/UDP | UDP 5060 |
| SIP/TLS | TCP 5061 |
| SIP/WS | TCP 5080 |
| SIP/WSS | TCP 5443 |
| RTP 中继 | UDP 10000–10099 |
| 会议 RTP | UDP 10100–10199 |
| 语音信箱 RTP | UDP 10200–10299 |
| TURN/UDP | UDP 3478 |
| TURN/TLS | TCP 5349 |
浏览器(SIP.js)──WSS 5443──┐
SIP 电话 ─────────UDP 5060──┼──► SIP 处理器 (Rust)
SIP 电话(TLS) ──TLS 5061──┘ │
┌────▼────┐ ┌──────────────────┐
│ 注册器 │ │ WebRTC 媒体网关 │
│ 代理 │ │ (webrtc-rs B2BUA │
│ 在线状态│ │ ICE+DTLS-SRTP) │
└────┬────┘ └──────────────────┘
│
┌─────────▼──────────┐
│ MySQL 8.0 │
└─────────┬──────────┘
│
管理界面 ──HTTP 8030──► Nginx ────────► REST API :3000
在 Linphone、Zoiper 等 SIP 客户端中配置:
| 字段 | 值 |
|---|---|
| SIP 服务器 | sip.air32.cn |
| 端口 | 5060 (UDP) / 5061 (TLS) |
| 协议 | UDP / TLS / WebSocket |
| 域名 | sip.air32.cn |
| 用户名 | 1001 |
| 密码 | password123 |
浏览器用户访问 /phone 页面,输入 SIP 账号密码即可直接发起语音或浏览器到浏览器视频通话。
- 投递规则:启用信箱的用户离线时立即接入语音信箱;在线但无人接听时,默认 25 秒后接入(
SIP3__SERVER__VOICEMAIL_NO_ANSWER_SECS)。 - 信箱访问:用户从自己的 SIP 账号拨打
*97可进入信箱端点并听到问候/就绪提示;完整留言播放和信箱导航为后续工作。 - 编解码:RTP/AVP 接收 G.711 PCMU/PCMA、G.722 宽带和 Opus(RFC 7587 单声道);录音统一以 16 kHz canonical WAV 存储,播放时按协商采样率重采样。MVP 不支持 SRTP/SAVP、视频或浏览器/WebRTC 语音信箱。
- MWI:终端可发送
SUBSCRIBE Event: message-summary订阅消息等待指示,SIP3 通过NOTIFY推送新/已保存留言数量。 - 存储目录:留言以 WAV 文件保存在
SIP3__SERVER__VOICEMAIL_STORAGE_DIR(Docker 默认/app/voicemail,宿主机挂载./voicemail);提示音从SIP3__SERVER__VOICEMAIL_PROMPT_DIR读取(默认voicemail/prompts)。 - RTP 端口:语音信箱媒体默认使用 UDP
10200-10299(SIP3__SERVER__VOICEMAIL_RTP_PORT_MIN/MAX),需单独放行并映射。 - DTMF 控制:当前 MVP 仅支持录音过程中按
#停止录音。播放菜单中的1重播、2/#下一条、7删除、9保存、*返回/退出尚未实现,属于计划功能。 - MVP 不包含:完整留言播放 IVR/导航/保存/删除、信箱 PIN、忙线转信箱、邮件通知、SRTP、浏览器/WebRTC 语音信箱。
# 本地 CI 对齐检查(推荐在 push 前执行)
pwsh ./scripts/local-ci.ps1
# 后端构建和测试
cd backend
cargo fmt --check
cargo build
cargo test
cargo clippy -- -D warnings
# 前端开发
cd frontend
npm install
npm run dev # 开发服务器 :5173- 不响铃 / MESSAGE 收不到:优先核对
sip_registrations中source_ip/source_port是否与实时来包一致。 - 接通无声音:确认 UDP
10000-10099已放行,并核对 SDP 中继端口与实际 RTP 源端口一致。 - Linphone 视频无画面:确认 INVITE 和 200 OK 的 SDP 都把
m=video改写到 SIP3 公网 IP 和中继端口。SIP 音视频通话每路会占用 4 个 RTP 中继端口,因此默认端口范围支持的并发视频通话少于纯音频通话。浏览器 WebRTC 视频不属于传统 SIP RTP 中继路径。 - 浏览器↔Linphone 视频无画面:确认 Linphone 已启用视频、浏览器已授予摄像头权限,并且 WSS/TURN 可达;同时检查 SIP INVITE/200 OK 的 SDP 中
m=video为活动状态(不是m=video 0),且中继 RTP 端口可达。 - 会议无声音 / 无法入会:确认会议室已启用、终端提供 RTP/AVP PCMU/PCMA、G.722 或单声道 Opus,并放行 UDP
10100-10199。可通过/api/metrics上sip3_conference_codec_total{codec="..."}观察服务端实际协商的编解码。 - 语音信箱不接听 / MWI 不更新:确认信箱已启用、呼叫/订阅来源与有效注册源一致,UDP
10200-10299已放行,提示音和存储目录可读写。 - MESSAGE 入库报 1146:确认已执行迁移
010_sip_messages.sql。
重要:
SIP3__SERVER__PUBLIC_IP建议配置为公网 数字 IPv4(例如154.8.159.79),避免终端因 SDP 中使用域名导致兼容问题。
详细部署和 TLS 配置指南请参阅 docs/deployment.md。