← 返回 AI 学习专题库 · 公开阅读版:实验结果与合成测试音可在线查看。原始抓包、脚本和日志保留在本地实战包;命令中的 /path/to/sipnab-lab 需替换为自己的目录。
AI LEARNING / NETWORK LAB研究截点 2026.09.08
SIP → SDP → RTP → EVIDENCE

Sipnab
使用与实战专题

把信令与媒体放回同一通电话里。通过六个可复现样本,学会读呼叫、查质量,也看清自动诊断能回答到哪一步。

6 组合成实战TUI + CLI + MCPWireshark 独立对照3 份真实导出 WAV
00 / EXPERIMENT RESULTS

先看实战:工具读数与原始证据

适合作为 SIP/RTP 排查入口。对当前版本,建议同时检查原始流指标、抓包完整性与音频内容。

乱序被累计为丢包

500 个序列全部到齐,却报 74.77% loss。已用独立解析和源码核对。

“无问题”不覆盖所有指标

10% 丢包被 problems 命中,analyze 和单呼叫 Issues 仍写无问题。

高 MOS 仍可能是静音

静音流得到 4.358 分,导出后左声道 80000 个采样全为零。

切换实验场景

A→B 真实缺包0独立序列号核对 / 包
Sipnab 报告丢包率74.77%A→B,最终读数
Sipnab 估计 MOS1.000非人工主观评分
A / B 到达包数500 / 500分别为两个媒体方向
真实序列缺失
0.00%
Sipnab loss
74.77%
同一个 A→B 流,横轴 0–100%。真实缺包按此固定样本完整序列集合计算;不代表接收端抖动缓冲是否丢弃迟到包。

展开当前样本的实测数据与自动分析原文

全部为本地合成 PCAP,实际运行 Sipnab 后取得结果。未连接生产电话系统,也未进行网卡实时抓包。数字固定于 v0.5.159。

AUDIO / EXPORTED BY SIPNAB

听一听导出的媒体

通过 Sipnab 的 MCP export_audio 实际生成。左声道为 A→B,右声道为 B→A;下方都是合成测试音。

正常双向

左:A→B,440Hz;右:B→A,660Hz。两个方向各 10 秒。

下载 WAV · 8kHz / 16bit / 双声道

10% 丢包

左侧每 10 包少 1 包。重建音频不等于接收端实际 PLC 播放。

下载 WAV · 8kHz / 16bit / 双声道

左声道全静音

左声道 RMS=0,右声道有音;两个流的 MOS 都约为 4.358。

下载 WAV · 8kHz / 16bit / 双声道

双声道文件即使左侧静音,右侧仍会有声音。音频验证使用解码后的 RMS 与样本数;未做主观听感评分。

1. 它是什么,边界在哪里

【官方文档+源码】Sipnab 是 Rust 实现的 SIP/RTP 捕获和分析工具,不是电话交换机,也不是 SIP 呼叫发起器。它把 Call-ID、SIP 状态和 SDP 中的媒体地址/端口关联到 RTP 流;也能在缺少可匹配信令时保留孤立媒体流。[S1][S3]

从一个呼叫的生命周期理解它:

  1. 取得输入:离线 PCAP/PCAPNG、网卡抓包或 HEP 镜像。
  2. 解封装与重组:链路/IP/传输层解析,必要时处理 IP 分片和 TCP SIP 分帧。
  3. 整理信令:解析 SIP,按呼叫上下文维护状态、消息、响应码、时间指标和 SDP offer/answer。
  4. 关联媒体:利用协商信息关联 RTP;观察 SSRC、payload type、序列号、时间戳、到达时间、包数、丢包和抖动。
  5. 读取结果:TUI、CLI/JSON、REST、MCP 和 Prometheus 使用共享分析存储,但具体字段和诊断覆盖必须逐个输出入口核对。

【能力已公开,未实测】HEP、REST、Prometheus、TLS/SRTP 解密、安全检测、多腿关联、PCAPNG、复杂封装、Opus 等。MIT OR Apache-2.0 双许可由同版本 Cargo.toml 和发布包内两份许可证确认。GitHub 仓库摘要的单一许可证标签不完整。[S1][S2][S3]

2. 本机怎么使用

已完成的本地安装

本机为 macOS ARM64,使用官方 sipnab-0.5.159-aarch64-apple-darwin.tar.gz。未编译 Rust,未安装新的全局包,二进制和音频插件仅放在 sipnab-lab/bin/。发布包 SHA-256 与 GitHub Release API 中的 digest 相同:

843315ed3e5caaa16991fab712da7bf8a385fcbdc798ebb3a56fafe4967bb5ad

这证明下载内容与该次 GitHub 发布记录相符,不等于独立签名审计。本次未执行 gh attestation verify。版本详情、下载 URL、时间和校验结果在 evidence/release.jsonevidence/install-verification.json[S2]

cd '/path/to/sipnab-lab'
./bin/sipnab --version
./bin/sipnab --no-config -I fixtures/baseline.pcap

--no-config 忽略宿主已有配置,使本实验使用相同默认值。离线 -I 模式不需要 sudo。这里的 shell 命令以本实验目录为工作目录。[S4]

其他机器的安装方法(文档路径,未逐平台实测)

环境 方法 适用条件
macOS brew install NormB/tap/sipnab 官方 Homebrew tap;使用后以 sipnab --version 核对真实版本
Linux x86_64/ARM64 从 Release 选择匹配架构的 deb/rpm 或 tar.gz GNU 包要求 glibc 2.36+ 与 libpcap;不要用 macOS 二进制
Linux 老发行版 选择对应 unknown-linux-musl 发布说明标注静态版本;不含 TUI 音频播放
源码构建 cargo build --release --features full 本版本文档要求 Rust 1.97+、libpcap 开发头文件;默认源码特性集不等于完整发布包

本次 --version 实际列出 native,tui,audio,tls,hep,api,mcp,mcp-http,metrics,plugins,vcon。macOS 抓实时网卡需要 BPF 访问权限;Linux 需要相应抓包权限。[S1][S2][S4]

3. 十分钟上手:先看信令,再看媒体

TUI 操作路线

所在位置 按键 用途
Call List ↑/↓ 或 j/k → Enter 选择呼叫并进入 SIP 时序图
Call Flow j/k;Enter;Esc 逐条读消息;查看原始消息;返回
Call Flow d 切换 SDP 展示,核对 c=、m=audio、codec、ptime
Call Flow m → 移到后续消息 → M 标记起点、看时间差、清除标记
Call List Tab 进入 RTP Streams
Call Flow r 进入该呼叫的 RTP 流列表
RTP Streams Enter 看单流详情:丢包、抖动、MOS、RTT/延迟假设
RTP/Stream Detail F2 保存 WAV;本次实际 WAV 导出使用 MCP
多个视图 F1 查询当前视图快捷键;某些按键随视图而变
Call List q,然后 y 退出;本次已实际走通

【本地实测】本次使用丢包样本走通 Call List → Enter → Call Flow → r → RTP Streams → Enter → Stream Detail → 退出。终端记录 results/tui-session.ansi 显示 450 包、丢失 50 包、10.00% loss、MOS 2.2(Bad),并显示 delay 100ms assumed。其他表中按键依据官方 walkthrough,未逐键实测。[S5][L4]

批量命令:知道每一种输出是什么

# 全部呼叫、每条一个 JSON 对象,便于脚本读取
./bin/sipnab --no-config -N -I fixtures/loss-10pct.pcap \
  --json-dialogs --no-cli-print > results/my-calls.ndjson

# 筛出诊断别名命中的呼叫;还要检查原始指标
./bin/sipnab --no-config -N -I fixtures/loss-10pct.pcap \
  --problems --json-dialogs --no-cli-print

# 单通电话报告
./bin/sipnab --no-config -N -I fixtures/loss-10pct.pcap \
  --call-report 'loss-10pct@sipnab-lab.invalid' \
  --markdown --no-cli-print

# 精确过滤:这个版本的 DSL 使用 rtp.loss(百分数)
./bin/sipnab --no-config -N -I fixtures/loss-10pct.pcap \
  --filter 'rtp.loss > 5' --json-dialogs --no-cli-print

# 缺一个媒体方向、信令失败
./bin/sipnab --no-config -N -I fixtures/one-way.pcap \
  --one-way --report --no-cli-print
./bin/sipnab --no-config -N -I fixtures/busy-486.pcap \
  --filter "state == 'Failed'" --report --no-cli-print

-I 是大写字母 I;-N 是非交互;--json 是每条 SIP 消息一个对象,--json-dialogs 才是每个 dialog 一个对象;--no-cli-print 防止普通消息输出混入结构化报告。本次的 per-dialog NDJSON 没有 MOS 字段,MCP rtp_stats 才提供本报告使用的 MOS。[S4][S6][L1]

过滤有两层:BPF 决定哪些包进入分析,--filter 决定哪些呼叫显示。如果 BPF 只写 port 5060,RTP 动态端口会被提前丢弃。--portrange 则是 SIP 识别端口范围,不能把它当 RTP 媒体范围。[S4][S6]

4. 六组实战设计与结果

【实验设定】无真实号码、无生产连接、无网卡抓包。Python 直接生成 PCAP 字节,不发送 UDP。地址使用文档地址 192.0.2.10/20,Call-ID 使用 .invalid。信令走 UDP/5060,媒体走 UDP/4000 与 5000;PT=0、PCMU/8000、ptime=20ms,SSRC 分别 0x11111111 / 0x22222222。两个方向基准音分别为 440/660 Hz。没有 RTCP,MOS 使用 Sipnab 默认的 100ms 单向路径延迟假设。

正常呼叫时间线:INVITE 0ms → 100 Trying 50ms → 180 Ringing 200ms → 200 OK 500ms → ACK 510ms → 首个 RTP 600/602ms → BYE 11000ms → 200 OK 11020ms。每个方向 500 包、每包 160 个采样点,合计 10 秒音频;Sipnab 的 duration_sec=11.02 是该 dialog 的观察跨度,不能直接当接通后的通话时长。

样本 注入条件 A/B 到达包数 A→B 真实缺包 Sipnab A→B loss A→B MOS --problems
baseline 无故障 500/500 0 0.00% 4.358 未命中
loss-10pct A→B 每 10 包去掉第 6 包 450/500 50 10.00% 2.228 命中
jitter-reorder A→B 奇数索引包额外延迟 120ms,保留全部包 500/500 0 74.77% 1.000 命中
one-way 删除 B→A 全部媒体,保留双向 SIP 500/0 A→B 为 0 0.00% 4.358 命中
silent-payload A→B 的 160 字节音频载荷全部为 0xFF 500/500 0 0.00% 4.358 未命中
busy-486 486 Busy Here + ACK,不建立媒体 0/0 不适用 不适用 不适用 命中

表中 MOS 是 Sipnab 的模型估计,没有做人工主观 MOS、PESQ 或 POLQA。乱序行的 MOS 受错误丢包输入污染,不能当听感结论;单向流的高 MOS 只描述存在的那个流,不替缺失方向评分。[L1][L2]

发现 A:乱序统计为何出错

独立脚本从 PCAP 解析 RTP 序列:500 个唯一序列、1000–1499 连续齐全、0 重复、247 次序列回退;每个相邻逻辑包的 RTP 时间戳增量仍为 160。Wireshark 4.6.7 同样显示 500 包、0 丢包,并标记乱序问题。[L2]

【源码核对】src/rtp/stream.rs:811–831last_seq + 1 计算缺口,较小前向 gap 立即累加到 lost_packets,随后无条件把 last_seq 更新为新到达包的序号;该更新路径没有在迟到包补齐时扣回。这解释本样本中的累加高估。[S7]

同样本还产生 Ptime asymmetry: 10 ms vs 20 ms 提示,但两端 SDP 都声明 20ms,且真实 RTP 逻辑时间戳都是每包 160/8000=20ms。这条提示也不能据此归因为真实重分包或中间设备。 抖动读数(Sipnab 最终 98.88ms、Wireshark mean 47.875ms)口径和乱序处理不同,不把它们直接判为同一指标不一致。

发现 B:自动摘要不是全覆盖质量检查

loss-10pct 的原始流指标已准确显示 10%,--problems 与 MCP find_problems 都选中这通电话,但 --analyze 与 call-report 的 Issues 没有对应提示。[L1]

【源码核对】该版本 analysis.rsFindingKind 枚举没有纯 RTP loss/jitter 类别;call_report.rs 的 Issues 只依据 diagnosis.hints 是否为空。DSL problems 则直接包含 rtp.loss > loss_bad_pctrtp.jitter > jitter_bad_ms[S8][S9]

用法:同时保留 per-stream 指标与筛选结果;不要把文本中的 No problems found 或进程退出码 0 当作业务质量合格。退出码主要反映执行是否成功,而非呼叫有无故障。[S4]

发现 C:传输正常仍可以是静音

silent-payload 的两个方向均被正确关联,MOS 都约 4.358,one_way_audio=false。MCP 导出的 8kHz、16bit、双声道、10秒 WAV 左声道 80000 个采样全部为零,右声道正常。测得 RMS 为 0 / 6344.33。[L3]

【解释】本模型的输入是网络侧丢包、抖动、codec 损伤参数和路径延迟,不检查词语是否说出来、TTS 是否正确生成、音量是否合理。CN/PT13 的静默跟踪也不能等同于识别所有 PCMU 零载荷。高 MOS、双向都有 RTP、200 OK 都不能代替媒体内容检查。[S7][S10]

对单向与 486 的正确解读

one-way 被标记 one_way_audio=true;这证明本抓包视点缺少反向媒体。真实排障仍需排除镜像漏采、非对称路由、direct media、hold/sendonly、VAD/舒适噪声等情形,不能单凭这一点断定接收端真的无声。

busy-486 的状态为 Failed,最终响应 486;它是合法的忙线结果,不必然是网络或软件故障。本实验还验证 SIP 失败时无媒体不会被自动理解为“已经接通但无媒体”。

5. MCP 实战与音频导出

【本地实测】使用临时 stdio 子进程,执行 initialize → tools/list → capture_status → rtp_stats → find_problems;在三个保留载荷的进程中执行 export_audio。实测工具列表共 65 个。没有把它注册到任何常驻 AI 客户端,也没有打开 HTTP MCP 监听端口。[L3]

# 临时 MCP 进程;它等待 JSON-RPC 请求,不是普通文本输出命令
./bin/sipnab --no-config -I fixtures/baseline.pcap --mcp --quiet \
  --retain-audio --mcp-file-root ./results/audio

# 已提供的客户端脚本完成协议握手与查询;运行后自动结束子进程
python3 scripts/run_mcp.py

关键调用参数:

{"name":"rtp_stats","arguments":{"call_id":"baseline@sipnab-lab.invalid"}}
{"name":"export_audio","arguments":{"call_id":"baseline@sipnab-lab.invalid","filename":"baseline.wav"}}

这是 tools/call 的 params 内容,不是完整 JSON-RPC 握手。完整实现见 scripts/mcp_probe.py,实际请求响应见 results/*-mcp-transcript.json

操作要点:

  • 先看 capture_status.source_exhausted=truesource_stopped_early=false,避免把尚未读完的文件当全量结果。
  • 核对 orphaned_stream_count、undecodable/snapped frames、端口过滤与 retention cap;它们描述本次捕获是否完整。
  • --retain-audio 才让批量 MCP 进程保存载荷;没有载荷留存,导出失败不能解释为原通话没音频。
  • 音频文件限定到 --mcp-file-root。本次实测已有同名文件会被拒绝覆盖;脚本对固定样本重跑复用现有 WAV 和原始 export_audio 回执。
  • --json-dialogs、MCP rtp_stats、TUI 是不同输出表面;先检查真实 schema 再写解析脚本。mos_grounded 说明模型参数的来源资格,不等于人工听测。
  • 这三个 WAV 是从观测到的 RTP 重建的双声道测试音,不是终端原生录音;丢包填补、抖动缓冲、PLC 和实际播放效果可能不同。

6. 用到 FreeSWITCH / AI 语音链路时,怎么安排

【工程建议,未连接生产】推荐先收齐一个已知问题呼叫的信令与媒体 PCAP,在工单中记录抓包点、Call-ID、起止时间、两条腿/通道标识、codec 与 ptime。把 Sipnab 作为离线第一遍分析,再用 Wireshark 与音频工具复核。

  1. 呼叫建立慢:看 INVITE→100/180/200 的时间,不把 180 的 PDD、接通 setup、首个媒体时延混为一个指标。检查 SIP 重传及最终错误码。
  2. 只一侧听不到:先确定抓包点应当可见双向媒体,再比对 SDP 的 c=/m=audio 与实际四元组;查 NAT、SBC 媒体锚点、direct media 和 ACL。只镜像 HEP 信令时,不会凭空得到完整 RTP 质量。
  3. TTS 卡顿/断续:分别看生成侧 PCM、送入交换机的媒体、交换机出侧 RTP、接收端反馈;Sipnab 可观察其中 SIP/RTP 段,不能直接证明 TTS 首包慢、应用排队或模型生成出错。
  4. 双向包正常但无声:导出对应方向的 WAV,查 RMS、连续静音段、样本数与音频时长;需要判断说话内容时再加 VAD/ASR。先确认 G.711 PCMU/PCMA、采样率和转码配置。
  5. 多中心/SBC 多腿:保存各抓包点原始证据。Call-ID 可能被 B2BUA 改写,扩展关联需依据可见头字段和业务标识核对;不能把同一 call-id 就等同于所有交换机内部 UUID。

实时抓包命令模板(本次未执行;按授权接口和实际地址改写):

# Linux 上两端 SIP 与媒体都经同一个可观察地址时的示例
# 文档地址 192.0.2.10 必须替换为真实且获授权的抓包对象
sudo sipnab --no-config -d eth0 -O call.pcap 'host 192.0.2.10 and udp'

如果信令和媒体 IP 不同,应把已知的相关地址纳入 BPF;如果是 SIP/TCP 则不能只抓 UDP。macOS 先用 tcpdump -D 确认真实接口名。使用适当捕获窗口并保留退出时的丢包统计;抓取范围过窄会失去证据,过大又可能使本机抓包掉包。[S4]

TLS/SRTP:普通密文 PCAP 不会自动变成明文。官方提供 keylog、特定 RSA 交换、SDES/SRTP、DTLS-SRTP 等路径,要求对应构建能力和可用密钥;RSA 私钥路径不适用于 ECDHE/PFS。uprobes 属于 Linux 相关路径,本次没有实测。内容可见性应在抓包设计时确认,而不是分析失败后推定“没有信令/媒体”。[S11]

7. 如何完整复现

cd '/path/to/sipnab-lab'
python3 scripts/generate_fixtures.py
python3 scripts/run_cli.py
python3 scripts/run_mcp.py
python3 scripts/verify_results.py

生成器和验证器只使用 Python 标准库。run_cli.py 中的 tshark 路径是本机 Wireshark.app 路径,其他系统需要按安装路径改写。Sipnab 二进制仅适用于本机的 macOS ARM64。已有 WAV 会保留;需要改变样本时应使用新的输出目录并同步生成新的导出回执。

检查包数/关联/序列完整性之外,还保存了 38 个初始 CLI 命令的返回码、stdout 与 stderr。进程均正常退出;“命令成功”与“诊断正确”分开评价。附加筛选和多核复核记录在 results/extra-checks.json。本任务不修补上游源码,也未向上游发送 issue。

实验限制:仅短呼叫、合成音、UDP/IPv4/PCMU;没有实网、长期压测、真实人声、主观音质、TCP 重传、复杂 NAT、SRTP、Opus、多个交换机或网络单向时延测量。独立核对证明的是当前文件中的包与载荷,不能证明生产接收端的播放体验。

8. 来源与证据台账

所有在线文档按 v0.5.159 固定,读取日期 2026-09-08。官方文档与源码来自同一项目,不能当成彼此独立的第三方背书;实战结论用本地原始 PCAP 和 Wireshark 交叉检查。

ID 来源 支持内容
S1 官方 README 产品、功能、构建特性和运行要求
S2 v0.5.159 ReleaseCargo.toml 发布日期、下载包、校验、MIT OR Apache-2.0
S3 架构 输入、处理链、DialogStore/StreamStore、输出共享
S4 安装CLI 安装、命令、默认阈值、退出码、输入过滤
S5 TUI walkthrough按键 TUI 操作路径
S6 输出格式DSL 消息/呼叫 JSON、过滤方式
S7 stream.rs 累计 gap、last_seq 更新、CN 跟踪
S8 analysis.rsdsl.rs 自动分析与 problems 筛选覆盖差异
S9 call_report.rs Issues 依赖 diagnosis.hints
S10 MOS 文档quality.rs 简化 E-model、codec 参数、延迟假设与适用边界
S11 TLS 捕获 解密条件;本次未实测
S12 MCP工具说明 stdio、查询、音频留存与导出
L1 verified-summary(本地文件)命令记录(本地文件) 六组实测、Sipnab 原始输出
L2 生成器(本地文件)独立验证器(本地文件)乱序 tshark 输出(本地文件) 已知输入、序列去重/缺失、独立解析
L3 MCP 工具 schema(本地文件)results/*-mcp-*.jsonresults/audio/*.wav 真正调用、真正导出、声道 RMS
L4 TUI 终端记录(本地文件) 实际交互与单流显示结果

工作区组织参考 [[projects/ai-learning]](知识日期 2026-08-30),只用于交付约定;Sipnab 的事实均以本次资料和实战为准。