简介:这份资源面向希望基于Chrome浏览器构建网页版SIP客户端的开发者与呼叫中心技术人员,提供了一套可直接运行的WebRTC语音通信原型。包内共25个文件,以14个JavaScript脚本为核心,配合2个CSS样式、5个PNG图标、3个WAV提示音及1个HTML入口页面,整体约426KB,结构轻量便于二次开发。其中SIPml-api.js负责与SIP服务器交互,实现注册、呼叫与挂断等信令逻辑;前端脚本与样式支撑界面渲染,音频文件则提供拨号音、回铃音与按键音等通话反馈。目前已有593人学习下载,适合想快速验证网页软电话或搭建Web呼叫中心原型的读者参考,可在此基础上扩展注册鉴权、通话状态管理与HTTPS加密传输等能力。
1. 拆开这个 290024 压缩包:Chrome 里跑网页 SIP 到底靠什么
很多人第一次看到「chrome浏览器网页版SIP」这类资源,会下意识以为是个 Chrome 插件,装上就能打电话。实际拆开chrome浏览器网页版SIP(290024).rar你会发现,它根本不是插件,而是一套纯前端的网页软电话原型:一个index.html入口,一个SIPml-api.js信令库,加上 Bootstrap 那套老 UI 和几个 wav 提示音。它解决的是「不装桌面软电话、直接在浏览器标签页里注册 SIP 账号并呼叫」这件事,面向的是做呼叫中心坐席页、Web 软电话、SIP 对接联调的开发者。核心链路是 SIP over WebSocket 负责信令、WebRTC 负责媒体,Chrome 只是承载 WebRTC 的容器。下面按「它是什么 → 怎么跑起来 → 坑在哪 → 怎么验证」一层层拆,新手能照着复现,熟手能直接看参数边界。
2. SIP over WebSocket 与 WebRTC 分工:先搞懂信令和媒体为什么分开
2.1 为什么浏览器里的 SIP 必须走 WebSocket
传统 SIP 软电话走 UDP/TCP 5060,浏览器里根本拿不到裸 socket,所以网页 SIP 的信令通道只能换成 WebSocket,也就是常说的 SIP over WS(安全场景是 WSS)。SIPml-api.js干的就是把 SIP 的 REGISTER、INVITE、BYE 这些方法封装成 JS 能调的接口,底层通过new WebSocket('wss://...')连到信令服务器。这里有个反直觉的点:SIP 只负责「叫谁、怎么接、什么时候挂」,真正传声音的是 WebRTC 的RTCPeerConnection,两者是分开的两条路。SIP 的 SDP 里携带的媒体描述,会被SIPml-api.js转成 WebRTC 能吃的 offer/answer。所以你在 Chrome 里听到声音,靠的不是 SIP 服务器转发媒体,而是浏览器之间或浏览器到媒体网关的 RTP 流。
常见做法是信令服务器同时提供 WS 端口和 SIP 注册能力,媒体走 WebRTC 的 ICE 打洞或 TURN 中继。这个压缩包里没有服务端,只有前端,意味着你必须自己准备一套支持 WS 的 SIP 服务器(比如常见的软交换或 IMS 侧配置),否则index.html打开后只会停在「正在连接」。
2.2 压缩包里的文件各自管什么
先把目录结构理清楚,不然改代码时容易找错文件。资源里能直接看到的文件大致分四类:
| 文件/目录 | 作用 | 是否要改 |
|---|---|---|
index.html | 页面入口,含 UI 和初始化调用 | 要改配置 |
SIPml-api.js | SIP 信令封装库 | 一般不动 |
js/下 bootstrap-*.js、jquery.js | UI 交互和弹窗、折叠等 | 不动 |
assets/css/、img/ | 样式和图标 | 按需换 |
sounds/ | ringtone、ringbacktone、dtmf 提示音 | 可替换 |
images/ | 图标资源 | 可替换 |
SIPml-api.js是黑匣子,除非你要改底层行为,否则只调它的 API。真正要动的是index.html里的初始化参数:WebSocket 地址、SIP 域、账号、密码。Bootstrap 那堆 js 只是让界面能弹窗、能折叠,跟通话逻辑无关,别在这上面浪费时间。
2.3 最小可跑的初始化代码长什么样
下面这段是网页 SIP 客户端最核心的初始化逻辑,参数按你自己的服务器填。注意SIPml-api.js的 API 命名在不同版本略有差异,以你包里的实际函数名为准,这里给的是通用写法:
// 初始化 SIP 栈,先探测 WebRTC 支持 SIPml.init(function () { // 创建 SIP 会话对象 var sipStack = new SIPml.Stack({ realm: 'your.sip.domain', // SIP 域,通常是服务器域名 impi: '1001', // 认证用户名 impu: 'sip:1001@your.sip.domain', // SIP URI password: 'your_password', // 账号密码 websocket_proxy_url: 'wss://your.sip.domain:7443', // 信令 WS 地址 enable_rtcweb_breaker: false, // 是否启用 WebRTC 兼容层 events_listener: { events: '*', listener: onSipEvent } // 事件回调 }); sipStack.start(); // 启动,触发 REGISTER }); // 统一事件回调,注册/呼叫/挂断都从这里出 function onSipEvent(e) { switch (e.type) { case 'started': console.log('栈已启动'); break; case 'connected': console.log('WS 已连接'); break; case 'registered': console.log('注册成功'); break; case 'registration_failed': console.warn('注册失败', e.description); break; case 'i_new_call': console.log('来电', e.session); break; } }逻辑说明:SIPml.init先确认浏览器支持 WebRTC,再new SIPml.Stack建栈,start()会依次触发 WS 连接和 REGISTER。参数里websocket_proxy_url必须和服务器实际监听的 WS/WSS 端口一致,realm和impu的域名要对得上,否则服务器直接回 403。events_listener用'*'接所有事件,调试阶段别只接 registered,不然注册失败你连原因都看不到。
2.4 发起呼叫和挂断的调用方式
注册成功后,呼叫就是一行new SIPml.Session.Call:
// 发起音频呼叫 var callSession = new SIPml.Session.Call( 'sip:1002@your.sip.domain', // 被叫 URI null, // 视频参数,音频传 null { audio: true, video: false } // 媒体约束 ); // 挂断 callSession.hangup({ description: '正常挂断' });参数说明:第二个参数传视频配置,纯语音呼叫传null或{ video: false };媒体约束里audio: true才会触发麦克风授权。Chrome 对getUserMedia有硬性要求——页面必须是 HTTPS 或 localhost,用file://直接打开index.html麦克风会被拒,这是新手第一个翻车点。
3. 把 index.html 跑起来:本地起服务、改配置、看日志
3.1 为什么不能双击打开 index.html
Chrome 对getUserMedia和 WebSocket 的安全策略决定了:file://协议下麦克风授权直接失败,WSS 也可能被拦。正确做法是本地起一个静态服务,用http://localhost或https://访问。最省事的是 Python 自带的 http.server:
# 在解压后的目录里执行,端口随意 python3 -m http.server 8080 # 然后浏览器访问 http://localhost:8080/index.html如果你要连的是 WSS 信令服务器,本地服务最好也上 HTTPS,否则 Chrome 会报混合内容(mixed content)拦截。自签证书本地测试可以,但要在 Chrome 里手动信任,或者用chrome://flags里相关开关临时放行——生产环境别这么干。
3.2 改配置前先确认服务器侧三件事
在动index.html之前,先跟信令服务器侧确认三件事,不然改半天都是白改:
- WS/WSS 监听端口是多少,路径是不是根路径(有些服务器要求
/ws)。 - SIP 域(realm)和账号 URI 的域名是否一致。
- 服务器是否要求特定的 SIP 传输标记,比如
transport=ws。
这三条任何一条对不上,现象都是「WS 连上了但注册失败」或「WS 根本连不上」。我一般会先用浏览器控制台看 Network 里的 WS 帧,确认 REGISTER 有没有发出去、服务器回了什么状态码。
3.3 用控制台定位注册失败
Chrome DevTools 的 Network 面板切到 WS,能看到 SIP 信令的收发帧。常见状态码对应关系:
| 状态码 | 含义 | 排查方向 |
|---|---|---|
| 403 | 认证失败 | 账号密码、realm、impu 是否匹配 |
| 404 | 用户不存在 | 服务器侧是否建了该分机 |
| 408 | 超时 | WS 地址或端口不通 |
| 500 | 服务器内部错误 | 看服务器日志,多半是配置问题 |
SIPml-api.js的事件回调里registration_failed会带description,把它打出来比猜快得多。如果 WS 帧里连 REGISTER 都没有,说明start()没触发或 WS 没连上,先查websocket_proxy_url。
3.4 提示音和 DTMF 怎么接
sounds/里的ringtone.wav、ringbacktone.wav、dtmf.wav是本地提示音,跟 WebRTC 媒体流是两回事。回铃音一般在呼叫发起后本地播放,接通后停掉;DTMF 按键音可以本地播,但真正传号要走 SIP INFO 或 RFC2833,具体看服务器支持哪种。别指望改 wav 文件就能改拨号方式,那只是听觉反馈。
// 呼叫发起后播回铃音,接通事件里停掉 var ringback = new Audio('sounds/ringbacktone.wav'); ringback.loop = true; ringback.play(); // 在 onSipEvent 的 'connected' 或媒体流事件里 ringback.pause();4. 避坑与排查:网页 SIP 最容易翻车的五个点
4.1 现象:麦克风授权弹窗不出现,直接失败
原因:页面不是 HTTPS 或 localhost,Chrome 直接拒绝getUserMedia。 解决:本地用http://localhost起服务,线上必须 HTTPS。别用file://调试。
4.2 现象:WS 连上但一直注册失败 403
原因:realm、impu、impi三者域名或账号对不上,或密码错。 解决:把三个字段和服务器侧分机配置逐字核对,注意impu要带sip:前缀和完整域名。
4.3 现象:能注册,一呼叫就断
原因:媒体协商失败,多半是 ICE 没打通或没有 TURN 中继,NAT 环境下尤其常见。 解决:确认服务器侧是否配了 STUN/TURN,SIPml-api.js的 iceServers 配置是否填了。纯内网测试可以先关掉 ICE 看是不是这个问题。
4.4 现象:Chrome 控制台报混合内容拦截
原因:页面是 HTTPS,但websocket_proxy_url写的是ws://。 解决:统一成wss://,或本地测试时页面也用 HTTP。
4.5 现象:Bootstrap 样式错乱、弹窗不弹
原因:assets/css或js/路径被改动,或 jQuery 加载顺序错。 解决:确认index.html里 css/js 引用路径和实际目录一致,jQuery 必须在 bootstrap 的 js 之前加载。
5. 进阶验证:用 chrome://webrtc-internals 看媒体到底通没通
注册成功、呼叫也建立了,不代表声音真的通了。判断媒体是否真正传输,最硬核的办法是打开chrome://webrtc-internals,这是 Chrome 内置的 WebRTC 黑匣子,能看到每条RTCPeerConnection的 ICE 状态、候选地址、收发字节数。具体看三处:ICE connection state 是不是connected或completed;bytesReceived和bytesSent是否在增长;audioLevel有没有非零值。如果 ICE 卡在checking,基本是 NAT 或防火墙问题;如果字节数一直是 0,说明 SDP 协商出来的媒体方向不对,回去查 offer/answer。
我一般还会配合一个笨办法:在onSipEvent里把每个事件类型和 session 状态都打上时间戳,跟webrtc-internals的时间线对齐,这样能快速区分是信令慢还是媒体没起来。另外,SIPml-api.js这类库对 Chrome 版本比较敏感,太新的 Chrome 可能改了某些 WebRTC 行为,遇到玄学问题时先换一个稳定版 Chrome 复现,别一上来就怀疑代码。从那以后我每次接网页 SIP 项目,都强制先跑一遍webrtc-internals确认媒体链路,再谈业务逻辑。希望帮到你。
本文还有配套的精品资源,点击获取