# wvp-gb28181 **Repository Path**: njqt/wvp-gb28181-talk ## Basic Information - **Project Name**: wvp-gb28181 - **Description**: 基于gb28181的摄像头实现方案代码 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 18 - **Created**: 2024-08-17 - **Last Updated**: 2024-08-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 国标28181对讲实现思路以及注意事项 标准国标对讲信令 - 流程图 ![对讲流程](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2Fduijiangliucheng.png) - 具体信令描述 ```shell #广播通知 BroadCast #平台侧------->设备侧 MESSAGE sip:34020000001110000001@3402000000 SIP/2.0 From: ;tag=bccedfd000006 To: Content-Length: 176 CSeq: 5 MESSAGE Route: Call-ID: 12345678900006 Via: SIP/2.0/UDP 192.168.1.101:5060;wlsscid=377aa9afcf1b36f;branch=123133532300006 Content-Type: Application/MANSCDP+xml Max-Forwards: 70 Broadcast 17298 34020000002000000001 34020000001370000001 ``` ```shell #设备测收到广播通知回复200 ok #设备测------>平台侧 SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.1.101:5060;wlsscid=377aa9afcf1b36f;branch=123133532300006 From: ;tag=bccedfd000006 To: ;tag=880670885 Call-ID: 12345678900006 CSeq: 5 MESSAGE User-Agent: IP Camera Content-Length: 0 ``` ```shell #设备测主动发起invite #设备测------>平台侧 INVITE sip:34020000002000000001@192.168.1.101:5060 SIP/2.0 Via: SIP/2.0/UDP 192.168.1.64:5060;rport;branch=z9hG4bK1490643408 From: ;tag=1499847265 // To: Call-ID: 1420309512 CSeq: 20 INVITE Contact: Content-Type: application/sdp Max-Forwards: 70 User-Agent: IP Camera # 媒体流发送者ID:发送方媒体流序列号,媒体流接收者ID:接收方媒体流序列号 Subject: 34020000002000000001:1,34020000001110000001:2 Content-Length: 214 v=0 o=34020000001110000001 2418 2418 IN IP4 192.168.1.64 s=Play c=IN IP4 192.168.1.64 t=0 0 # 音频 端口 RTP-over-UDP 负载类型( 8-PCMA, 96-PS) # 注意 这一步就是设备侧开的收语音流数据的端口 # RTP/AVP传输模式是udp,这种只能在局域网对讲 # TCP/RTP/AVP 这种才可以在公网对讲 m=audio 15062 RTP/AVP 8 96 a=recvonly # RTP + 音频流: 负载类型 a=rtpmap:8 PCMA/8000 a=rtpmap:96 PS/90000 # SSRC(同步信源标识符): SSRC值由媒体流发送设备所在的SIP监控域产生,作为媒体流的标识使用 y=0200000017 # v/编码格式/分辨率/帧率/码率类型/码率大小 a/编码格式/码率大小/采样率 # G.711 / 64kbps / 8kHz f=v/a/1/8/1 ``` ```shell #平台侧回复invite ok #平台侧------->设备侧 》》》》》》 IPC SIP/2.0 200 OK From: ;tag=1499847265 To: ;tag=1420309512 Call-ID: 1420309512 CSeq: 20 INVITE User-Agent: General SIP UAS V1.0 Via: SIP/2.0/UDP 192.168.1.64:5060;rport;branch=z9hG4bK1490643408 Contact: Content-Type: application/SDP Content-Length: 182 v=0 o=34020000002000000001 0 0 IN IP4 192.168.1.101 s=Play c=IN IP4 192.168.1.101 t=0 0 # 这是我们平台侧开的端口,使用这个端口发送音频数据到设备 m=audio 8000 RTP/AVP 8 // 端口:8000 a=rtpmap:8 PCMA/8000 //rtpmap:8 PCMA及g711a 采样率:8000HZ a=sendonly y=0200000017 ``` ```shell #设备测------>平台侧 ACK sip:34020000002000000001@192.168.1.101:5060 SIP/2.0 Via: SIP/2.0/UDP 192.168.1.64:5060;rport;branch=z9hG4bK106578989 From: ;tag=1499847265 To: ;tag=1420309512 Call-ID: 1420309512 CSeq: 20 ACK Contact: Max-Forwards: 70 User-Agent: IP Camera Content-Length: 0 #这一步过后我们就可以发送音频数据了 ``` - 关闭对讲 ```shell # 发送BYE信令 BYE sip:34020000001370000001@3402000000 SIP/2.0 From: ;tag=1420309512 To: ;tag=1499847265 CSeq: 2 BYE Call-ID: 1420309512 Via: SIP/2.0/UDP 192.168.1.64:5060;branch=z9hG4bKee5c5d98-00007 Max-Forwards: 70 Content-Length: 0 ``` ``` # BYE ok SIP/2.0 200 OK Via: SIP/2.0/UDP 192.168.1.64:5060;branch=z9hG4bKee5c5d98-00007;received=192.168.1.101 From: ;tag=1420309512 To: ;tag=1499847265 Call-ID: 1420309512 CSeq: 2 BYE User-Agent: IP Camera Content-Length: 0 ``` 大华TALK对讲模式 - 流程图 ![](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2Fdahua-talk.png) - 具体信令 ```shell #主动发送invite到摄像机 #平台侧------->设备侧 INVITE sip:34020000001370000001@3402000000 SIP/2.0 Via: SIP/2.0/UDP 192.168.32.33:14000;rport;branch=z9hG4bK7d0821ae From: ;tag=1752762308 To: Call-ID: 1949196054 CSeq: 5 INVITE Content-Type: APPLICATION/SDP Contact: Max-forwards: 70 User-Agent: tiamaes Subject: 34020000001370000001:2,34020000002000000033:2 Content-Length: 183 v=0 o=34020000002000000033 0 0 IN IP4 192.168.32.33 s=Talk c=IN IP4 192.168.32.33 t=0 0 # 此处我们可以控制数据的传输方式 可以使用 TCP/RTP/AVP # 25000 是平台侧发送语音数据的端口 m=audio 25000 TCP/RTP/AVP 8 a=sendrecv a=rtpmap:8 PCMA/8000 f=v/a/1/8/1 y=0200000002 ``` ```shell #设备回复invite ok #设备测------>平台侧 SIP/2.0 100 Trying Call-ID: 1949196054 Content-Length: 0 CSeq: 5 INVITE From: ;tag=1752762308 To: User-Agent: SIP UAS V3.0.0.1049939 Via: SIP/2.0/UDP 192.168.32.33:14000;rport=14000;branch=z9hG4bK7d0821ae SIP/2.0 101 Dialog Establishment Call-ID: 1949196054 Contact: Content-Length: 0 CSeq: 5 INVITE From: ;tag=1752762308 To: ;tag=5aaf5dffc1105842785cdf093029bcf8 User-Agent: SIP UAS V3.0.0.1049939 Via: SIP/2.0/UDP 192.168.32.33:14000;rport=14000;branch=z9hG4bK7d0821ae SIP/2.0 200 OK Call-ID: 1949196054 Contact: Content-Length: 270 Content-Type: application/sdp CSeq: 5 INVITE From: ;tag=1752762308 To: ;tag=5aaf5dffc1105842785cdf093029bcf8 User-Agent: SIP UAS V3.0.0.1049939 Via: SIP/2.0/UDP 192.168.32.33:14000;rport=14000;branch=z9hG4bK7d0821ae v=0 o=34020000001310000001 0 0 IN IP4 192.168.32.13 s=Talk i=VCam Talk Session c=IN IP4 192.168.32.13 t=0 0 # 9712是设备测开的接收语音数据流的端口 m=audio 9712 TCP/RTP/AVP 8 a=recvonly a=rtpmap:8 PCMA/8000/1 m=audio 9712 TCP/RTP/AVP 8 a=sendonly a=rtpmap:8 PCMA/8000/1 y=0200000002 f=v/0/0/0/0/0a/0/0/0 ``` ```shell #发送ack到摄像机 ACK sip:34020000001370000001@3402000000 SIP/2.0 Via: SIP/2.0/UDP 192.168.32.33:14000;rport;branch=z9hG4bK6e554aa5 From: ;tag=1752762308 To: ;tag=5aaf5dffc1105842785cdf093029bcf8 Call-ID: 1949196054 CSeq: 5 ACK Contact: Max-forwards: 70 User-Agent: tiamaes Content-Length: 0 # 这一步进行完就可以对讲了 ``` > **通过对比国标标准信令和大华talk信令我们可以看出,标准的国标对讲sip信令,invite是设备测发起,我们没有办法控制数据的传输模式,而大华的talk模式invite是平台侧发起,我们可以控制数据的传输模式使用udp还是tcp(当然也得设备测支持tcp传输模式才可,要不然还是白扯)** 实现思路流程图 - **文字语言描述** 1. 点击对讲按钮,客户端根据zlmediakit的规则生成webrtc推流地址 2. 调用麦克风,通过webrtc推语音流到zlmediakit 3. 如果推流成功,开始调用wvp国标信令协商接口进行对讲信令协商(说通俗点就是告诉设备测我现在要进行语音对讲,你开个端口用于接收语音数据,我开个端口用于发送语音数据),如果推流失败,则在客户端提示用户具体原因 4. 国标对讲信令协商成功,我们就可以开始讲话,设备侧就可以听到,如果失败,具体原因具体分析。 5. 再次点击按钮,停止对讲,停止推流,发送bye信令,断开连接,关闭端口 - **对讲流程图** ![](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2Fduijiangliucheng.jpg) - **关键节点** 1. 推流地址是如何确认的(这个是zlmeida提供的一个api接口)参考[zlmedia webrtc推流](https://github.com/ZLMediaKit/ZLMediaKit/wiki/webrtc%E4%BF%A1%E4%BB%A4%E4%BA%A4%E4%BA%92%E6%A0%BC%E5%BC%8F) ​ ![](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2Fzlwebrtctl.jpg) 参数(自己定义): app:audio stream:deviceid+channelid type:push 2.信令协商完成后如何把推到zlmedia的流再推给设备,也是调用zl的api主要涉及两个api - udp ![](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2FsatrtSendRtp.jpg) - TCP被动模式调用这个 ![](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2FstartSendRtpPassive.jpg) 对讲源码分析 > 说明:涉及的api接口都在TalkbackController这个类中 1.获取推流地址(如果开启了推流鉴权需要加上参数sign,这一块我是写死的) ``` java /** * 获取webrtc推流地址 * @param deviceId * @param channelId * @return */ @GetMapping("/getWebRtcAddr/{deviceId}/{channelId}") public WVPResult getWebRtcAddr(@PathVariable("deviceId") String deviceId, @PathVariable("channelId") String channelId) { //首先判断设备是否正在对讲 if (redisCatchStorage.isBroadcastItem(deviceId)) { return WVPResult.fail(ErrorCode.ERROR603); } Device device = deviceService.getDevice(deviceId); MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device); if (mediaServerItem == null) { logger.error("流媒体未找到"); return WVPResult.fail(ErrorCode.ERROR600); } Map result = new HashMap<>(16); String app = "audio"; String stream = deviceId + "_" + channelId; String type = "push"; LoginUser userInfo = SecurityUtils.getUserInfo(); String sign = Md5Utils.hash(userService.getUserByUsername(userInfo.getUsername()).getPushKey()); //获取推流鉴权密钥 //示例 https://192.168.126.111:9443/index/api/webrtc?app=live&stream=test&type=play&sign=... String sdpIp; if (!ObjectUtils.isEmpty(device.getSdpIp())) { sdpIp = device.getSdpIp(); }else { sdpIp = mediaServerItem.getSdpIp(); } String webRtcPushUrl = String.format("https://%s:%s/index/api/webrtc?app=%s&stream=%s&type=%s&sign=%s", sdpIp, mediaServerItem.getHttpSSlPort(), app, stream, type,sign); result.put("app",app); result.put("stream",stream); result.put("type",type); result.put("sign",sign); result.put("webRtcPushUrl", webRtcPushUrl); logger.info("获取webrtc推流地址:{}",webRtcPushUrl); return WVPResult.success(result); } ``` 2.下发国标信令接口,只贴出关键点 - **broadcast** ![](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2Fstart1.jpg) ![](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2Fsatrt2.jpg) - 设备invite ![1685004717697](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2Finvite_startSendRtp.png) 3. 关于对讲的讨论大家可以参考这个issue,这里边是我和作者的讨论 [对讲参考issue](https://github.com/ZLMediaKit/ZLMediaKit/issues/2217) 对讲的必要条件,重要!!! 1. 网站必须得是https,因为浏览器安全机制,如果网站不是https,调用不起来计算机设备,也就是麦克风,如果开启了https,**因为我们大多数都是自签名证书,需要信任证书才可以进入网站,zlmedia的https站点我们也需要信任一下,**要不然我们没办法往zlmedia推流 - spring boot配置https ![](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2Fspringboothttps.jpg) 2. **通道的音频选项需要打开,现在默认设备上线就是打开的** ![](https://image-1318164152.cos.ap-nanjing.myqcloud.com/wvp-pro-talk-redme%2Fchannel1.jpg) > **说明:如果没有满足这两个需求,对讲按钮是不能点击的,悬浮会有提示**