单通外呼线路测试
独立程序 sip-call,默认执行普通单通线路测试;可显式使用 --ai,从本地 task/provider 文件调用现有 AI 与媒体流程并将录音保存在本地。它不进入 Agent/Dispatcher 调度业务流程,不接 SaaS/MQ,不发布任务反馈,不上传 OSS,不排队、不自动重拨或换线。
使用
make build-sip-call
cp cmd/sip-call/sip.env.example sip-xx.env
chmod 600 sip-xx.env
# 填写服务商确认的线路参数及本机 Asterisk 路径后执行:
./dist/sip-call sip-xx.env 18601010101
# 需要本通抓包与 SIP/RTP 证据时:
./dist/sip-call -D sip-xx.env 18601010101
# 显式测试一个 task_config 的 AI 组合(本地 JSON 文件均须为当前用户所有且 0600):
./dist/sip-call --ai --task task.json --provider providers.json sip-xx.env 18601010101
命令格式为 sip-call [--debug|-D] [--ai --task task.json --provider providers.json] <线路.env> <原始号码>,不再支持 call 子命令或 --sip 参数。--debug 与 -D 等价。--task 必须是当前共享合同的完整 task_config 资源,--provider 必须是完整 ai_providers 资源;两者由当前合同校验,任务声明工作模式(当前支持 asr_only / full_ai)。没有 --ai 时,--task 或 --provider 会明确报错,其他普通命令行为不变。环境安装统一预装 tcpdump/tshark(生产与测试相同);预装不等于开启抓包。默认模式不调用或检查这些工具;调试模式要求两者可执行、指定接口可抓包且权限充分。调试抓包未就绪或在 Dial 前已退出就不拨号。参数后的号码是原始号码,仅添加该文件声明的前缀一次;不要自己先加线路前缀。
运行 AI 模式会真实拨号并调用任务指定的 AI 服务。每次真实执行都须另获线路、号码及 AI 请求的明确授权;本文示例不是授权。 安装二进制和准备配置不等于允许执行呼叫;部署阶段不拨号、不请求真实 AI,也不修改 Asterisk 或业务服务。
标准用户目录
测试机配置统一放在 ~/.sip-call/,目录和每项用途见 deploys/test/sip-call-home/README.md:ai/providers.json 存完整 SaaS ai_providers 资源,task/<task_id>.json 存完整 task_config,sip/ 存线路 ENV,results/ 存每次运行输出。配置目录为 0700,含凭据的 JSON/ENV 为 0600;不要放入 Git、聊天或普通日志。
示例调用:
~/.local/bin/sip-call --ai \
--task "$HOME/.sip-call/task/<task_id>.json" \
--provider "$HOME/.sip-call/ai/providers.json" \
"$HOME/.sip-call/sip/<line>.env" <原始号码>
线路 ENV 的 OUTPUT_DIR 应指向 $HOME/.sip-call/results 的绝对路径。此命令会实际拨号并请求 AI;部署验收只检查文件/权限及 --help,不执行该命令。
运行条件
- 在已有原生 Asterisk 的主机运行;已有
asterisk.conf、0600 的pjsip.conf、原生 PJSIP/ARI 模块及私有ari-secret。 pjsip.conf须预先配置且仅配置一次#tryinclude sip-call-managed.conf。这是主机的一次性准备;工具不会自动补写,缺少或重复入口就拒绝执行。该临时文件不存在时,Asterisk 正常忽略此入口。- 以 Asterisk 配置的所属用户运行(登记测试机为
rogee),不要sudo sip-call。root 或文件归属不匹配会在创建结果、抓包及改配置前明确拒绝;不自动改归属或放宽权限。 - 使用现有本地 ARI 用户
go-sip-agent和已配置的 loopback HTTP 地址;密码只从ASTERISK_CONFIG_DIR/ari-secret在内存读取,不复制到 ENV 或结果。 - 已有静态
go-sip-udpUDP transport,绑定0.0.0.0:5060;工具不更改静态 transport,不启动/重启 Asterisk。 - 不存在活动通话,且业务调用方、Agent/其他 ARI 应用已停止。工具拒绝接管业务应用;普通模式采用独立
sip-callARI 应用及siptest-<SIP_ID>endpoint。AI 模式复用现有 full-media ARI 呼叫入口,仍要求 Agent 和其他业务 ARI 应用停止。 - 只支持 IPv4、UDP、IP 鉴权、无需 REGISTER、PCMA(alaw)。其他方式明确拒绝,不猜测配置。
- 线路 ENV 为 0600 普通文件;task/provider JSON 文件也必须是当前用户所有的普通文件且权限为 0600;结果目录为 0700。每次命令传入的线路 ENV 直接决定所测线路,不与 task
allowed_trunk_ids匹配、不做自动选线、失败换线或重拨。所有线路配置项见sip.env.example;不读取 shell 环境覆盖线路,也不执行source。
调试抓包权限
主程序不提权。Linux 主机安装人员可仅为 tcpdump 设置抓包能力,生产与测试按同样方式准备:
sudo setcap cap_net_raw,cap_net_admin=eip /usr/bin/tcpdump
/usr/sbin/getcap /usr/bin/tcpdump
先确认该路径是主机实际安装的 tcpdump;不对 sip-call、tshark 或整个目录设置能力。普通用户仍使用前述不带 sudo 的 -D 命令。权限不足时不拨号、不回退到无抓包模式,输出“已请求,但未启动”;具体启动错误保留在本次私有 tcpdump.log。
自动配置与退出
取得该 Asterisk 配置目录的独占测试锁,确认空闲和固定入口已准备后,只创建本次专用 sip-call-managed.conf,其中包含独立 endpoint/AOR。工具不改写、不备份 pjsip.conf,也不修改原有业务线路;输入的 SIP.env 只读且保留。使用原生 module reload res_pjsip.so 并核对明确的成功响应,不依赖可选的 pjsip reload 别名,不把 CLI 退出码 0 当作加载成功;随后核对实际服务地址、主叫、codec、transport 和 context。通过才执行一次原生 ARI Dial。
收到真正的 Up 和 StasisStart 才记录接通。普通模式按 HOLD_SECONDS 保持后挂断;AI 模式使用 task 的 ring_timeout_ms、max_call_duration_ms 和对话设置,不按 HOLD_SECONDS 截断。观察到通道结束或挂断后的 ARI 404 才记录结束确认。正常结束后,仅删除本次专用配置、reload 并确认 endpoint 和 AOR 均已移除,不改 go-sip-managed.conf 或业务 SIP 加载代次。临时文件使用原配置的所属用户/组和 0600;清理前核对原配置及临时文件的内容、归属和权限,reload 后再次核对原配置,发生变化则明确报错,不覆盖或删除变化后的文件。
已有 sip-call-managed.conf、并发配置修改或未知通道状态均报错。Ctrl-C 会取消 AI 媒体流程并请求结束通话,但中断本身不作为结束证据;只有确认结束后才恢复临时线路配置。无法确认结束时保留临时配置及本次结果/证据供人工排查,不要直接重跑或自行清理。清理、抓包停止或证据解析失败都保留错误并以非零退出,不报告“全部正常”。
~/sip-call/tool-backups/ 是安装时保存的旧版工具和来源清单,不是 SIP 配置备份,也不是拨号必需目录。本次修改不删除这些旧工具或任何历史证据。
输出与证据
归属与输入检查通过后创建独立私有目录,此后的成功或失败均有 result.json(检查未通过时不创建结果):线路、服务地址、主叫、原始/线路被叫、SIP Call-ID、拨号前绑定时间、接通时间、结束确认时间、AI 模式、本地录音路径、最终状态及失败原因。AI 模式将实际录音保存为 recording.wav;ASR 转写和 LLM 回复只输出到当前终端,不写入 result.json 或普通日志。终端可能包含通话内容,勿转存到普通日志或聊天。
开启调试后另有:
capture.pcap与 SHA-256:只抓指定 SIP 服务端 IP 的 UDP,避免复制其他主机流量。tcpdump.log:本通抓包工具的启动/退出信息。sip.tsv:真实 tshark 按本通 Call-ID 解出的 SIP 时间线;最终响应进一步匹配原始 INVITE 的 CSeq 与 Via branch,不能把 BYE 的 200 当作接通。rtp.tsv:依据该通 SDP 音频端口识别的 RTP 包及字节;结果明确记录观察范围。
SIP 服务端与媒体服务器使用不同 IP 时,这个窄过滤器不覆盖另一个媒体 IP;未观察到 RTP 不能据此断言无媒体。裸线路测试不发送合成语音、不验证双向音质,RTP 包存在也不等于语音/AI 正常。
调试模式观察到原生接通但没有同一原始 INVITE 的真实 2xx 最终响应时,保留原生接通/结束事实,同时明确报告抓证失败,不给出完整成功结论。
未开调试时只报告原生通道事实,不编造 SIP 状态码、媒体事实或抓包证据。原始抓包可能含用户音频,配置副本也须私密保存;不要复制到聊天、普通日志或 Git。
Agent 的调试参数
sip-go-agent agent --mode nonprod-real --capture
普通 Agent 默认不依赖 tcpdump,不校验外部抓包凭证。--capture 则复用 nonprod-call-evidence.sh:脚本提前开启抓包与 PJSIP logger,Agent 核对 AGENT_EVIDENCE_ROOT 下绑定本通 event/线路/原始号码的活跃凭证。调试条件缺失拒绝拨号;脚本不会因为新增参数而自动启动。
--capture 仅属于 Agent,Dispatcher 不接受。Dispatcher、Agent 的 --debug/-D 均只开启详细日志,不与抓包联动;独立 sip-call 的 --debug/-D 仍保留本文原有抓包含义。业务授权、任务/线路时段、额度和 HEP 原生 SIP 响应采集规则未取消;没有 tcpdump 不等于绕过业务门禁。
本地验证范围
单元测试覆盖普通模式兼容、AI 参数和本地配置校验、task/provider 绑定、显式线路 ENV、AI 模式选择、真实媒体/录音适配、未知结束保护及本地结果输出。网络隔离的测试不会调用真实 AI 服务或真实线路;现有 tcpdump/tshark 测试只对合成 pcap 离线解析,可用 GO_SIP_TSHARK_TEST_IMAGE 显式启用。
这些测试没有向真实线路发送 SIP,也不能证明线路接通、真实 AI 服务可用、SaaS 控制链路已修复或生产可发布。