跳到正文

浏览器软电话与坐席 SIP 接入

系统二的坐席可以直接在浏览器(callout-webpage 坐席通话台)用 SIP 软电话外呼客户, 全程获得实时字幕、打字转语音、保持 / 恢复、DTMF 与结束控制。本文说明这条链路的 组成、配置与接口;单个接口的请求 / 响应结构见 api-reference.md 「浏览器软电话与坐席 SIP」一组。

1. 链路组成

text
坐席浏览器 (callout-webpage 坐席通话台)
  │ 1. GET /api/agents/me/sip-config     ← 读取本坐席 SIP 注册参数
  │ 2. POST /api/softphone-sessions      ← 创建会话,拿 sessionId + sipExtraHeaders
  │ 3. SIP UA 经 sipWsUrl 注册后拨 softphone.serviceNumber(携带 sipExtraHeaders)

FreeSWITCH ──socket──▶ callflow-esl `browser-softphone-assist-business`
  │   按 SIP Header 里的 sessionId 找回会话 → 建独立会议(坐席=host)
  │   → originate 客户入会 → 开会议转写

callout-server(控制面代理,全部落 agent_call_records)
  │ GET  /api/softphone-sessions/:id/events    ← SSE:session / message / tts / error
  │ POST /api/softphone-sessions/:id/messages  ← 坐席打字文本 → TTS 注入客户腿
  │ POST /api/softphone-sessions/:id/controls  ← hold / resume / dtmf / transfer
  │ POST /api/softphone-sessions/:id/notes     ← 会话备注
  │ POST /api/softphone-sessions/:id/end       ← 结束会话

callout-server 自己不碰媒体流:会话的实时状态由 callflow-esl 的 browser-softphone-session-hub 维护(callflow-esl HTTP 端口上有一组同名内部端点, token 头鉴权),callout-server 只做代理 + 权限校验 + 旁路落库

2. 坐席 SIP 配置

callout.agents 表为每个坐席保存一组浏览器 SIP 注册参数:

字段说明
phoneExtension唯一 SIP 注册账号,同时也是 FreeSWITCH directory 用户、拨号分机和转人工标识
sipPasswordSIP 注册密码
sipRealmSIP realm / domain
sipWsUrlWebSocket SIP 地址(wss://.../ws,浏览器 UA 用)
sipDisplayName显示名
sipEnabled是否启用浏览器软电话(0/1

读取接口(均要求 agent:operate 权限):

  • GET /api/agents/me/sip-config:当前登录用户绑定坐席的 SIP 配置 (坐席与登录用户是一对一硬绑定,只认 agents.userId)。
  • GET /api/agents/sip-configs:当前用户可见的已启用 SIP 配置列表 (admin / supervisor 可见全部)。

坐席的创建 / 编辑接口(POST /api/agentsPATCH /api/agents/:agentId) 可写入上述 SIP 字段。启用软电话时,phoneExtensionsipPasswordsipRealmsipWsUrl 必须完整。

3. 会话生命周期

  1. 创建:前端 POST /api/softphone-sessions(携带客户号码与线路选择)。 callout-server 先落一条 agent_call_records,再请求 callflow-esl 创建 内存 Hub 会话,返回 sessionIdserviceNumbersipExtraHeaders
  2. 拨号:浏览器 SIP UA 拨 serviceNumber(配置 softphone.serviceNumber), 必须原样携带 sipExtraHeaders——callflow-esl 业务靠这些 Header 里的 sessionId / 客户号码找回会话;缺失会被播错误提示后挂断。
  3. 接通browser-softphone-assist-business 建会议(坐席=host)、开录音、 originate 客户入会(conference-guest-business),开启会议转写。
  4. 实时事件:前端订阅 GET /api/softphone-sessions/:id/events(SSE), 事件类型:session(状态 / 会议 / 录音信息)、message(按角色归并的 对话消息,实时字幕)、tts(打字消息的 queued/playing/completed/failed)、 error
  5. 控制messages(打字文本 TTS 注入客户腿)、controlshold / resume 对坐席腿 deaf/undeaf、dtmf 发客户腿、transfer 转接)、 notes(备注落库)。
  6. 结束:任一侧挂机或 POST .../end;转写片段写入 transcript_segments, 通话记录(含录音短文件名)保留在 agent_call_records,事后可查 GET /api/softphone-calls(列表)与 GET /api/softphone-calls/:id(详情)。

4. 配置

callout-server config.json

json
{
  "callflowEsl": {
    "baseUrl": "http://127.0.0.1:9912",
    "authToken": "esl-0x21"
  },
  "softphone": {
    "serviceNumber": "5020"
  }
}
字段说明
callflowEsl.baseUrlcallflow-esl HTTP 地址(其 http-server 端口,默认 9912),软电话会话代理的目标
callflowEsl.authToken与 callflow-esl http-server.authToken 对应的共享令牌,代理请求放在 token
softphone.serviceNumber浏览器 SIP UA 实际拨打的业务号(代码默认 8800,仓库配置 5020

环境变量覆盖:CALLOUT_CALLFLOW_ESL_BASE_URLCALLOUT_CALLFLOW_ESL_AUTH_TOKENCALLOUT_SOFTPHONE_SERVICE_NUMBER

FreeSWITCH 侧要求:serviceNumber 必须能经拨号计划进入 callflow-esl 的 outbound socket,并路由到 browser-softphone-assist-business(在 callflow.call_business_number_mappings 把该号码映射到此业务,或在拨号计划中 设置 business_code 通道变量);坐席 SIP 账号需在 FreeSWITCH directory 注册, 且开启 WebSocket(wss)SIP 入口。

ICE / TURN

两个软电话页面在 SIP 注册前调用受登录鉴权保护的 GET /api/softphone/ice-config。 仓库默认 turn.enabled=false,响应为 { enabled: false, iceServers: [], expiresAt: null },浏览器使用 host candidate 完成本地 直连。关闭状态不缓存、不安排刷新,后续注册、拨号或接听会重新请求,因此服务端启用 TURN 后无需等待旧状态过期。

生产环境启用 TURN 时,响应为 { enabled: true, iceServers: [...], expiresAt: "<ISO time>" },其中包含 STUN、 TURN/UDP、TURN/TCP 和 coturn REST 短期凭据。前端在过期前 5 分钟刷新,同一 callout 标签页的多个软电话组件共用一份凭据缓存。旧凭据过期且刷新失败时,新的注册、拨出与接听 会显示“ICE/TURN 配置获取失败”并在 SDP 创建前停止,不会静默降级为空数组。

TURN 直接监听 123.57.205.60:3478,relay 范围为 31000–31040/UDP,不经过 FRP。 shared secret 只能由服务器私有配置或 CALLOUT_TURN_SHARED_SECRET 注入。 必须同时提供 turn.enabled=true 与真实 shared secret;启用但配置不完整时接口返回 503 ICE_CONFIG_UNAVAILABLE。两种成功响应均使用 Cache-Control: no-store

5. 关联文档

  • 通话侧业务实现:apps/callflow-esl/docs/existing-businesses.mdbrowser-softphone-assist-business 一节
  • 接口请求 / 响应结构:api-reference.md
  • AI 通话转人工(会议 ACD,与本链路共用会议与坐席模型): transfer-to-human.md

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。