Commit 6b1d966255db75070f42b1e6a430ddff4299b248

Authored by 648540858
1 parent 4362a5b4

优化合并对讲broadcast级联模式

... ... @@ -6,7 +6,7 @@
6 6 <parent>
7 7 <groupId>org.springframework.boot</groupId>
8 8 <artifactId>spring-boot-starter-parent</artifactId>
9   - <version>2.7.2</version>
  9 + <version>2.7.9</version>
10 10 </parent>
11 11  
12 12 <groupId>com.genersoft</groupId>
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
... ... @@ -790,11 +790,11 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
790 790 content.append("t=0 0\r\n");
791 791  
792 792 if ("TCP-PASSIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
793   - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 8 96\r\n");
  793 + content.append("m=audio " + ssrcInfo.getPort() + " TCP/RTP/AVP 8 96\r\n");
794 794 } else if ("TCP-ACTIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
795   - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 8 96\r\n");
  795 + content.append("m=audio " + ssrcInfo.getPort() + " TCP/RTP/AVP 8 96\r\n");
796 796 } else if ("UDP".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
797   - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 8 96\r\n");
  797 + content.append("m=audio " + ssrcInfo.getPort() + " RTP/AVP 8 96\r\n");
798 798 }
799 799  
800 800 content.append("a=recvonly\r\n");
... ... @@ -817,12 +817,12 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
817 817 sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> {
818 818 streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
819 819 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  820 + subscribe.removeSubscribe(hookSubscribe);
820 821 errorEvent.response(e);
821 822 }), e -> {
822   - // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
823 823 ResponseEvent responseEvent = (ResponseEvent) e.event;
824 824 SIPResponse response = (SIPResponse) responseEvent.getResponse();
825   - streamSession.put(platform.getServerGBId(), channelId, callIdHeader.getCallId(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play);
  825 + streamSession.put(platform.getServerGBId(), channelId, callIdHeader.getCallId(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.broadcast);
826 826 okEvent.response(e);
827 827 });
828 828 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
... ... @@ -102,7 +102,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
102 102 }
103 103 String isUdp = sendRtpItem.isTcp() ? "0" : "1";
104 104 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
105   - logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
  105 + logger.info("收到ACK,rtp/{}开始级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
106 106 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
107 107 Map<String, Object> param = new HashMap<>(12);
108 108 param.put("vhost","__defaultVhost__");
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
... ... @@ -2,7 +2,10 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2  
3 3 import com.genersoft.iot.vmp.common.StreamInfo;
4 4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5   -import com.genersoft.iot.vmp.gb28181.bean.*;
  5 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  6 +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType;
  7 +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  8 +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
6 9 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
7 10 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
8 11 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
... ... @@ -24,9 +27,10 @@ import org.springframework.beans.factory.InitializingBean;
24 27 import org.springframework.beans.factory.annotation.Autowired;
25 28 import org.springframework.stereotype.Component;
26 29  
27   -import javax.sip.*;
  30 +import javax.sip.InvalidArgumentException;
  31 +import javax.sip.RequestEvent;
  32 +import javax.sip.SipException;
28 33 import javax.sip.address.SipURI;
29   -import javax.sip.header.CallIdHeader;
30 34 import javax.sip.header.FromHeader;
31 35 import javax.sip.header.HeaderAddress;
32 36 import javax.sip.header.ToHeader;
... ... @@ -87,13 +91,15 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
87 91 @Override
88 92 public void process(RequestEvent evt) {
89 93  
  94 + // TODO 此处需要重构
  95 + SIPRequest request =(SIPRequest) evt.getRequest();
90 96 try {
91   - responseAck((SIPRequest) evt.getRequest(), Response.OK);
  97 + responseAck(request, Response.OK);
92 98 } catch (SipException | InvalidArgumentException | ParseException e) {
93 99 logger.error("[回复BYE信息失败],{}", e.getMessage());
94 100 }
95   - CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
96   - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
  101 +
  102 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, request.getCallIdHeader().getCallId());
97 103  
98 104 if (sendRtpItem != null){
99 105 logger.info("[收到bye] {}/{}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId());
... ... @@ -115,7 +121,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
115 121 param.put("ssrc",sendRtpItem.getSsrc());
116 122 logger.info("[收到bye] 停止推流:{}", streamId);
117 123 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
118   - redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), callIdHeader.getCallId(), null);
  124 + redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), request.getCallIdHeader().getCallId(), null);
119 125 zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
120 126  
121 127 int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);
... ... @@ -159,7 +165,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
159 165 }
160 166 SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);
161 167 if (ssrcTransactionForPlay != null){
162   - if (ssrcTransactionForPlay.getCallId().equals(callIdHeader.getCallId())){
  168 + if (ssrcTransactionForPlay.getCallId().equals(request.getCallIdHeader().getCallId())){
163 169 // 释放ssrc
164 170 MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlay.getMediaServerId());
165 171 if (mediaServerItem != null) {
... ... @@ -168,7 +174,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
168 174 streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream());
169 175 }
170 176 }
171   - SsrcTransaction ssrcTransactionForPlayBack = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callIdHeader.getCallId(), null);
  177 + SsrcTransaction ssrcTransactionForPlayBack = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, request.getCallIdHeader().getCallId(), null);
172 178 if (ssrcTransactionForPlayBack != null) {
173 179 // 释放ssrc
174 180 MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlayBack.getMediaServerId());
... ... @@ -178,5 +184,32 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
178 184 streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlayBack.getStream());
179 185 }
180 186 }
  187 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, request.getCallIdHeader().getCallId(), null);
  188 + if (ssrcTransaction != null) {
  189 + // 释放ssrc
  190 + MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
  191 + if (mediaServerItem != null) {
  192 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc());
  193 + }
  194 +
  195 + switch (ssrcTransaction.getType()) {
  196 +// case play:
  197 +// break;
  198 +// case talk:
  199 +// break;
  200 +// case playback:
  201 +// break;
  202 +// case download:
  203 +// break;
  204 + case broadcast:
  205 + String deviceId = ssrcTransaction.getDeviceId();
  206 + String channelId1 = ssrcTransaction.getChannelId();
  207 + // 如果是
  208 + break;
  209 + default:
  210 + break;
  211 + }
  212 + streamSession.remove(device.getDeviceId(), channelId, ssrcTransaction.getStream());
  213 + }
181 214 }
182 215 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java
... ... @@ -102,6 +102,7 @@ public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent imp
102 102  
103 103 DeviceChannel deviceChannel = storage.queryChannelInParentPlatform(platform.getServerGBId(), targetId);
104 104 if (deviceChannel == null) {
  105 + logger.warn("[国标级联 语音喊话] 未找到通道 platform: {}, channel: {}", platform.getServerGBId(), targetId);
105 106 responseAck(request, Response.NOT_FOUND, "TargetID not found");
106 107 return;
107 108 }
... ... @@ -123,6 +124,7 @@ public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent imp
123 124 commanderForPlatform.broadcastResultCmd(platform, deviceChannel, sn, true, eventResult->{
124 125 logger.info("[国标级联] 语音喊话 回复失败 platform: {}, 错误:{}/{}", platform.getServerGBId(), eventResult.statusCode, eventResult.msg);
125 126 }, eventResult->{
  127 +
126 128 // 消息发送成功, 向上级发送invite,获取推流
127 129 try {
128 130 platformService.broadcastInvite(platform, deviceChannel.getChannelId(), mediaServerForMinimumLoad, (mediaServerItem, response)->{
... ... @@ -132,7 +134,7 @@ public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent imp
132 134 AudioBroadcastCatch broadcastCatch = audioBroadcastManager.get(device.getDeviceId(), targetId);
133 135 if (broadcastCatch != null ) {
134 136 if (playService.audioBroadcastInUse(device, targetId)) {
135   - logger.info("[国标级联] 语音喊话 设备正在使用中 platform: {}, channel: {}",
  137 + logger.info("[国标级联] 语音喊话 设备正在使用中 platform: {}, channel: {}",
136 138 platform.getServerGBId(), deviceChannel.getChannelId());
137 139 // 查看语音通道已经建立且已经占用 回复BYE
138 140 try {
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
... ... @@ -259,11 +259,11 @@ public class ZLMRTPServerFactory {
259 259 // 订阅 zlm启动事件, 新的zlm也会从这里进入系统
260 260 hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout,
261 261 (MediaServerItem mediaServerItem, JSONObject response)->{
262   - logger.info("[上级点播] {}->监听端口到期继续保持监听", ssrc);
  262 + logger.info("[保持端口] {}->监听端口到期继续保持监听", ssrc);
263 263 keepPort(serverItem, ssrc);
264 264 });
265 265 }
266   - logger.info("[上级点播] {}->监听端口: {}", ssrc, localPort);
  266 + logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort);
267 267 return localPort;
268 268 }
269 269  
... ... @@ -271,7 +271,7 @@ public class ZLMRTPServerFactory {
271 271 * 释放保持的端口
272 272 */
273 273 public boolean releasePort(MediaServerItem serverItem, String ssrc) {
274   - logger.info("[上级点播] {}->释放监听端口", ssrc);
  274 + logger.info("[保持端口] {}->释放监听端口", ssrc);
275 275 boolean closeRTPServerResult = closeRtpServer(serverItem, ssrc);
276 276 HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, serverItem.getId());
277 277 // 订阅 zlm启动事件, 新的zlm也会从这里进入系统
... ... @@ -357,7 +357,7 @@ public class ZLMRTPServerFactory {
357 357  
358 358 public JSONObject startSendRtp(MediaServerItem mediaInfo, SendRtpItem sendRtpItem) {
359 359 String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
360   - logger.info("rtp/{}开始向上级推流, 目标={}:{},SSRC={}", sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
  360 + logger.info("rtp/{}开始推流, 目标={}:{},SSRC={}", sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
361 361 Map<String, Object> param = new HashMap<>(12);
362 362 param.put("vhost","__defaultVhost__");
363 363 param.put("app",sendRtpItem.getApp());
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
... ... @@ -373,7 +373,7 @@ public class PlatformServiceImpl implements IPlatformService {
373 373 errorEvent.response(new SipSubscribe.EventResult(-1, "端口监听失败"));
374 374 return;
375 375 }
376   - logger.info("[国标级联] 发起语音喊话 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
  376 + logger.info("[国标级联] 语音喊话,发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
377 377 platform.getServerGBId(), channelId, ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), ssrcCheck);
378 378  
379 379 String timeOutTaskKey = UUID.randomUUID().toString();
... ... @@ -396,6 +396,7 @@ public class PlatformServiceImpl implements IPlatformService {
396 396 }
397 397 }, userSetting.getPlayTimeout());
398 398 commanderForPlatform.broadcastInviteCmd(platform, channelId, mediaServerItem, ssrcInfo, (mediaServerItemForInvite, response)->{
  399 + logger.info("[国标级联] 发起语音喊话 收到上级推流 deviceId: {}, channelId: {}", platform.getServerGBId(), channelId);
399 400 dynamicTask.stop(timeOutTaskKey);
400 401 // hook响应
401 402 playService.onPublishHandlerForPlay(mediaServerItemForInvite, response, platform.getServerGBId(), channelId);
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
... ... @@ -1183,7 +1183,7 @@ public class PlayServiceImpl implements IPlayService {
1183 1183  
1184 1184 String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
1185 1185 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
1186   - logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
  1186 + logger.info("收到ACK,rtp/{}开始推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
1187 1187 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
1188 1188 Map<String, Object> param = new HashMap<>(12);
1189 1189 param.put("vhost", "__defaultVhost__");
... ...
web_src/src/components/dialog/devicePlayer.vue
... ... @@ -181,7 +181,7 @@
181 181 style="font-size: 1.875rem;"></i></div>
182 182 <div style="position: absolute; left: 7.25rem; top: 3.25rem; font-size: 1.875rem;"
183 183 @mousedown="ptzCamera('zoomout')" @mouseup="ptzCamera('stop')"><i
184   - class="el-icon-zoom-out control-zoom-btn"></i></div>
  184 + class="el-icon-zoom-out control-zoom-btn"></i></div>
185 185 <div class="contro-speed" style="position: absolute; left: 4px; top: 7rem; width: 9rem;">
186 186 <el-slider v-model="controSpeed" :max="255"></el-slider>
187 187 </div>
... ... @@ -300,7 +300,8 @@
300 300 </el-tab-pane>
301 301 <el-tab-pane label="语音对讲" name="broadcast">
302 302 <div style="padding: 0 10px">
303   - <el-switch v-model="broadcastMode" :disabled="broadcastStatus !== -1" active-color="#409EFF" active-text="喊话"
  303 + <el-switch v-model="broadcastMode" :disabled="broadcastStatus !== -1" active-color="#409EFF"
  304 + active-text="喊话"
304 305 inactive-text="对讲"></el-switch>
305 306 </div>
306 307 <div class="trank" style="text-align: center;">
... ... @@ -565,20 +566,20 @@ export default {
565 566 this.tracks = []
566 567 let _this = this;
567 568 this.$copyText(data).then(
568   - function (e) {
569   - _this.$message({
570   - showClose: true,
571   - message: '复制成功',
572   - type: 'success'
573   - });
574   - },
575   - function (e) {
576   - _this.$message({
577   - showClose: true,
578   - message: '复制失败,请手动复制',
579   - type: 'error'
580   - });
581   - }
  569 + function (e) {
  570 + _this.$message({
  571 + showClose: true,
  572 + message: '复制成功',
  573 + type: 'success'
  574 + });
  575 + },
  576 + function (e) {
  577 + _this.$message({
  578 + showClose: true,
  579 + message: '复制失败,请手动复制',
  580 + type: 'error'
  581 + });
  582 + }
582 583 );
583 584 },
584 585 ptzCamera: function (command) {
... ... @@ -654,55 +655,54 @@ export default {
654 655 this.$axios({
655 656 method: 'get',
656 657 url: '/api/play/broadcast/' + this.deviceId + '/' + this.channelId + "?timeout=30&broadcastMode=" + this.broadcastMode
657   - }).then( (res)=> {
  658 + }).then((res) => {
658 659 if (res.data.code === 0) {
659 660 let streamInfo = res.data.data.streamInfo;
660 661 if (document.location.protocol.includes("https")) {
661 662 this.startBroadcast(streamInfo.rtcs)
662   - }else {
  663 + } else {
663 664 this.startBroadcast(streamInfo.rtc)
664 665 }
665   -
666   - }else {
667   - this.$message({
668   - showClose: true,
669   - message: res.data.msg,
670   - type: "error",
671   - });
672   - }
673   - });
674   - }else if (this.broadcastStatus === 1) {
675   - this.broadcastStatus = -1;
676   - this.broadcastRtc.close()
677   - }
678   - },
679   - startBroadcast(url){
680   - // 获取推流鉴权Key
681   - this.$axios({
682   - method: 'post',
683   - url: '/api/user/userInfo',
684   - }).then( (res)=> {
685   - if (res.data.code !== 0) {
686   - this.$message({
687   - showClose: true,
688   - message: "获取推流鉴权Key失败",
689   - type: "error",
690   - });
691   - this.broadcastStatus = -1;
692   - }else {
693   - let pushKey = res.data.data.pushKey;
694   - // 获取推流鉴权KEY
695   - url += "&sign=" + crypto.createHash('md5').update(pushKey, "utf8").digest('hex')
696   - console.log("开始语音喊话: " + url)
697   - this.broadcastRtc = new ZLMRTCClient.Endpoint({
698   - debug: true, // 是否打印日志
699   - zlmsdpUrl: url, //流地址
700   - simulecast: false,
701   - useCamera: false,
702   - audioEnable: true,
703   - videoEnable: false,
704   - recvOnly: false,
705   - })
  666 + } else {
  667 + this.$message({
  668 + showClose: true,
  669 + message: res.data.msg,
  670 + type: "error",
  671 + });
  672 + }
  673 + });
  674 + } else if (this.broadcastStatus === 1) {
  675 + this.broadcastStatus = -1;
  676 + this.broadcastRtc.close()
  677 + }
  678 + },
  679 + startBroadcast(url) {
  680 + // 获取推流鉴权Key
  681 + this.$axios({
  682 + method: 'post',
  683 + url: '/api/user/userInfo',
  684 + }).then((res) => {
  685 + if (res.data.code !== 0) {
  686 + this.$message({
  687 + showClose: true,
  688 + message: "获取推流鉴权Key失败",
  689 + type: "error",
  690 + });
  691 + this.broadcastStatus = -1;
  692 + } else {
  693 + let pushKey = res.data.data.pushKey;
  694 + // 获取推流鉴权KEY
  695 + url += "&sign=" + crypto.createHash('md5').update(pushKey, "utf8").digest('hex')
  696 + console.log("开始语音喊话: " + url)
  697 + this.broadcastRtc = new ZLMRTCClient.Endpoint({
  698 + debug: true, // 是否打印日志
  699 + zlmsdpUrl: url, //流地址
  700 + simulecast: false,
  701 + useCamera: false,
  702 + audioEnable: true,
  703 + videoEnable: false,
  704 + recvOnly: false,
  705 + })
706 706  
707 707 // webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,(e)=>{//获取到了远端流,可以播放
708 708 // console.error('播放成功',e.streams)
... ... @@ -715,15 +715,15 @@ export default {
715 715 // // this.eventcallbacK("LOCAL STREAM", "获取到了本地流")
716 716 // });
717 717  
718   - this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_NOT_SUPPORT,(e)=>{// 获取到了本地流
719   - console.error('不支持webrtc',e)
720   - this.$message({
721   - showClose: true,
722   - message: '不支持webrtc, 无法进行语音喊话',
723   - type: 'error'
724   - });
725   - this.broadcastStatus = -1;
726   - });
  718 + this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_NOT_SUPPORT, (e) => {// 获取到了本地流
  719 + console.error('不支持webrtc', e)
  720 + this.$message({
  721 + showClose: true,
  722 + message: '不支持webrtc, 无法进行语音喊话',
  723 + type: 'error'
  724 + });
  725 + this.broadcastStatus = -1;
  726 + });
727 727  
728 728 this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, (e) => {// ICE 协商出错
729 729 console.error('ICE 协商出错')
... ...