Commit 4604aaea99925415db8d9efe1d7e68d6f59e93c8

Authored by 648540858
1 parent 3571ca27

优化语音对讲支持根据设备设置释放收到ACK后开始发流

src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
... ... @@ -47,8 +47,6 @@ public class UserSetting {
47 47  
48 48 private Boolean syncChannelOnDeviceOnline = Boolean.FALSE;
49 49  
50   - private Boolean pushStreamAfterAck = Boolean.FALSE;
51   -
52 50 private Boolean sipLog = Boolean.FALSE;
53 51 private Boolean sqlLog = Boolean.FALSE;
54 52 private Boolean sendToPlatformsWhenIdLost = Boolean.FALSE;
... ... @@ -234,14 +232,6 @@ public class UserSetting {
234 232 this.broadcastForPlatform = broadcastForPlatform;
235 233 }
236 234  
237   - public Boolean getPushStreamAfterAck() {
238   - return pushStreamAfterAck;
239   - }
240   -
241   - public void setPushStreamAfterAck(Boolean pushStreamAfterAck) {
242   - this.pushStreamAfterAck = pushStreamAfterAck;
243   - }
244   -
245 235 public Boolean getSipUseSourceIpAsRemoteAddress() {
246 236 return sipUseSourceIpAsRemoteAddress;
247 237 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
... ... @@ -188,8 +188,8 @@ public class Device {
188 188 @Schema(description = "设备注册的事务信息")
189 189 private SipTransactionInfo sipTransactionInfo;
190 190  
191   -
192   -
  191 + @Schema(description = "控制语音对讲流程,释放收到ACK后发流")
  192 + private boolean broadcastPushAfterAck;
193 193  
194 194 public String getDeviceId() {
195 195 return deviceId;
... ... @@ -465,4 +465,11 @@ public class Device {
465 465 /*======================设备主子码流逻辑END=========================*/
466 466  
467 467  
  468 + public boolean isBroadcastPushAfterAck() {
  469 + return broadcastPushAfterAck;
  470 + }
  471 +
  472 + public void setBroadcastPushAfterAck(boolean broadcastPushAfterAck) {
  473 + this.broadcastPushAfterAck = broadcastPushAfterAck;
  474 + }
468 475 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
... ... @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
3 3 import com.alibaba.fastjson2.JSONObject;
4 4 import com.genersoft.iot.vmp.conf.DynamicTask;
5 5 import com.genersoft.iot.vmp.conf.UserSetting;
  6 +import com.genersoft.iot.vmp.gb28181.bean.Device;
6 7 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
7 8 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
8 9 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
... ... @@ -10,9 +11,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor
10 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
11 12 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
12 13 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
13   -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
14   -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
15 14 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  15 +import com.genersoft.iot.vmp.service.IDeviceService;
16 16 import com.genersoft.iot.vmp.service.IMediaServerService;
17 17 import com.genersoft.iot.vmp.service.IPlayService;
18 18 import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
... ... @@ -63,6 +63,9 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
63 63 private IVideoManagerStorage storager;
64 64  
65 65 @Autowired
  66 + private IDeviceService deviceService;
  67 +
  68 + @Autowired
66 69 private ZLMRTPServerFactory zlmrtpServerFactory;
67 70  
68 71 @Autowired
... ... @@ -87,40 +90,23 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
87 90 @Override
88 91 public void process(RequestEvent evt) {
89 92 CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
90   -
91   - String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
92   - logger.info("[收到ACK]: platformGbId->{}", platformGbId);
93   - if (userSetting.getPushStreamAfterAck()) {
94   - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformGbId);
95   - // 取消设置的超时任务
96   - dynamicTask.stop(callIdHeader.getCallId());
97   - String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
98   - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
99   - if (sendRtpItem == null) {
100   - logger.warn("[收到ACK]:未找到通道({})的推流信息", channelId);
101   - return;
102   - }
103   - String isUdp = sendRtpItem.isTcp() ? "0" : "1";
104   - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
105   - logger.info("收到ACK,rtp/{}开始级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
106   - sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
107   - Map<String, Object> param = new HashMap<>(12);
108   - param.put("vhost","__defaultVhost__");
109   - param.put("app",sendRtpItem.getApp());
110   - param.put("stream",sendRtpItem.getStream());
111   - param.put("ssrc", sendRtpItem.getSsrc());
112   - param.put("dst_url",sendRtpItem.getIp());
113   - param.put("dst_port", sendRtpItem.getPort());
114   - param.put("src_port", sendRtpItem.getLocalPort());
115   - param.put("pt", sendRtpItem.getPt());
116   - param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
117   - param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
118   - param.put("is_udp", isUdp);
119   - if (!sendRtpItem.isTcp()) {
120   - // udp模式下开启rtcp保活
121   - param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
122   - }
123   -
  93 + String fromUserId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
  94 + String toUserId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
  95 + logger.info("[收到ACK]: 来自->{}", fromUserId);
  96 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
  97 + if (sendRtpItem == null) {
  98 + logger.warn("[收到ACK]:未找到来自{},目标为({})的推流信息",fromUserId, toUserId);
  99 + return;
  100 + }
  101 + logger.info("[收到ACK]:rtp/{}开始级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
  102 + sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
  103 + // 取消设置的超时任务
  104 + dynamicTask.stop(callIdHeader.getCallId());
  105 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  106 + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(fromUserId);
  107 +
  108 + if (parentPlatform != null) {
  109 + Map<String, Object> param = getSendRtpParam(sendRtpItem);
124 110 if (mediaInfo == null) {
125 111 RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
126 112 sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStream(),
... ... @@ -130,30 +116,75 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
130 116 playService.startSendRtpStreamHand(sendRtpItem, parentPlatform, json, param, callIdHeader);
131 117 });
132 118 } else {
133   - // 如果是非严格模式,需要关闭端口占用
134   - JSONObject startSendRtpStreamResult = null;
135   - if (sendRtpItem.getLocalPort() != 0) {
136   - if (sendRtpItem.isTcpActive()) {
137   - startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
138   - }else {
139   - param.put("dst_url", sendRtpItem.getIp());
140   - param.put("dst_port", sendRtpItem.getPort());
141   - startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
142   - }
143   - }else {
144   - if (sendRtpItem.isTcpActive()) {
145   - startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
146   - }else {
147   - param.put("dst_url", sendRtpItem.getIp());
148   - param.put("dst_port", sendRtpItem.getPort());
149   - startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
150   - }
151   - }
  119 + JSONObject startSendRtpStreamResult = sendRtp(sendRtpItem, mediaInfo, param);
152 120 if (startSendRtpStreamResult != null) {
153 121 playService.startSendRtpStreamHand(sendRtpItem, parentPlatform, startSendRtpStreamResult, param, callIdHeader);
154 122 }
155 123 }
  124 + }else {
  125 + Device device = deviceService.getDevice(fromUserId);
  126 + if (device == null) {
  127 + logger.warn("[收到ACK]:来自{},目标为({})的推流信息为找到流体服务[{}]信息",fromUserId, toUserId, sendRtpItem.getMediaServerId());
  128 + return;
  129 + }
  130 + // 设置为收到ACK后发送语音的设备已经在发送200OK开始发流了
  131 + if (!device.isBroadcastPushAfterAck()) {
  132 + return;
  133 + }
  134 + if (mediaInfo == null) {
  135 + logger.warn("[收到ACK]:来自{},目标为({})的推流信息为找到流体服务[{}]信息",fromUserId, toUserId, sendRtpItem.getMediaServerId());
  136 + return;
  137 + }
  138 + Map<String, Object> param = getSendRtpParam(sendRtpItem);
  139 + JSONObject startSendRtpStreamResult = sendRtp(sendRtpItem, mediaInfo, param);
  140 + if (startSendRtpStreamResult != null) {
  141 + playService.startSendRtpStreamHand(sendRtpItem, device, startSendRtpStreamResult, param, callIdHeader);
  142 + }
  143 + }
  144 + }
  145 +
  146 + private Map<String, Object> getSendRtpParam(SendRtpItem sendRtpItem) {
  147 + String isUdp = sendRtpItem.isTcp() ? "0" : "1";
  148 + Map<String, Object> param = new HashMap<>(12);
  149 + param.put("vhost","__defaultVhost__");
  150 + param.put("app",sendRtpItem.getApp());
  151 + param.put("stream",sendRtpItem.getStream());
  152 + param.put("ssrc", sendRtpItem.getSsrc());
  153 + param.put("dst_url",sendRtpItem.getIp());
  154 + param.put("dst_port", sendRtpItem.getPort());
  155 + param.put("src_port", sendRtpItem.getLocalPort());
  156 + param.put("pt", sendRtpItem.getPt());
  157 + param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  158 + param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  159 + param.put("is_udp", isUdp);
  160 + if (!sendRtpItem.isTcp()) {
  161 + // udp模式下开启rtcp保活
  162 + param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
156 163 }
  164 + return param;
  165 + }
  166 +
  167 + private JSONObject sendRtp(SendRtpItem sendRtpItem, MediaServerItem mediaInfo, Map<String, Object> param){
  168 + JSONObject startSendRtpStreamResult = null;
  169 + if (sendRtpItem.getLocalPort() != 0) {
  170 + if (sendRtpItem.isTcpActive()) {
  171 + startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
  172 + }else {
  173 + param.put("dst_url", sendRtpItem.getIp());
  174 + param.put("dst_port", sendRtpItem.getPort());
  175 + startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  176 + }
  177 + }else {
  178 + if (sendRtpItem.isTcpActive()) {
  179 + startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
  180 + }else {
  181 + param.put("dst_url", sendRtpItem.getIp());
  182 + param.put("dst_port", sendRtpItem.getPort());
  183 + startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  184 + }
  185 + }
  186 + return startSendRtpStreamResult;
  187 +
157 188 }
158 189  
159 190 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
... ... @@ -427,23 +427,18 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
427 427  
428 428 try {
429 429 // 超时未收到Ack应该回复bye,当前等待时间为10秒
430   - if (userSetting.getPushStreamAfterAck()) {
431   - dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
432   - logger.info("Ack 等待超时");
433   - mediaServerService.releaseSsrc(mediaServerItemInUSe.getId(), sendRtpItem.getSsrc());
434   - // 回复bye
435   - try {
436   - cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId());
437   - } catch (SipException | InvalidArgumentException | ParseException e) {
438   - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
439   - }
440   - }, 60 * 1000);
441   - }
  430 + dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
  431 + logger.info("Ack 等待超时");
  432 + mediaServerService.releaseSsrc(mediaServerItemInUSe.getId(), sendRtpItem.getSsrc());
  433 + // 回复bye
  434 + try {
  435 + cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId());
  436 + } catch (SipException | InvalidArgumentException | ParseException e) {
  437 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  438 + }
  439 + }, 60 * 1000);
442 440  
443   - SIPResponse sipResponse = responseSdpAck(request, content.toString(), platform);
444   - if (!userSetting.getPushStreamAfterAck()) {
445   - playService.startPushStream(sendRtpItem, sipResponse, platform, request.getCallIdHeader());
446   - }
  441 + responseSdpAck(request, content.toString(), platform);
447 442 } catch (SipException | InvalidArgumentException | ParseException e) {
448 443 logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
449 444 }
... ... @@ -650,7 +645,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
650 645 if (response != null) {
651 646 sendRtpItem.setToTag(response.getToTag());
652 647 }
653   -
654 648 redisCatchStorage.updateSendRTPSever(sendRtpItem);
655 649  
656 650 } else {
... ... @@ -888,16 +882,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
888 882 content.append("f=\r\n");
889 883  
890 884 try {
891   - SIPResponse sipResponse = responseSdpAck(request, content.toString(), platform);
892   - if (!userSetting.getPushStreamAfterAck()) {
893   - playService.startPushStream(sendRtpItem, sipResponse, platform, request.getCallIdHeader());
894   - }
895   - return sipResponse;
896   - } catch (SipException e) {
897   - logger.error("未处理的异常 ", e);
898   - } catch (InvalidArgumentException e) {
899   - logger.error("未处理的异常 ", e);
900   - } catch (ParseException e) {
  885 + return responseSdpAck(request, content.toString(), platform);
  886 + } catch (SipException | InvalidArgumentException | ParseException e) {
901 887 logger.error("未处理的异常 ", e);
902 888 }
903 889 return null;
... ... @@ -1132,7 +1118,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1132 1118 audioBroadcastManager.update(audioBroadcastCatch);
1133 1119  
1134 1120 // 开启发流,大华在收到200OK后就会开始建立连接
1135   - if (!userSetting.getPushStreamAfterAck()) {
  1121 + if (!device.isBroadcastPushAfterAck()) {
1136 1122 playService.startPushStream(sendRtpItem, sipResponse, parentPlatform, request.getCallIdHeader());
1137 1123 }
1138 1124  
... ...
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
... ... @@ -64,7 +64,7 @@ public interface IPlayService {
64 64  
65 65 void startPushStream(SendRtpItem sendRtpItem, SIPResponse sipResponse, ParentPlatform platform, CallIdHeader callIdHeader);
66 66  
67   - void startSendRtpStreamHand(SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
  67 + void startSendRtpStreamHand(SendRtpItem sendRtpItem, Object correlationInfo,
68 68 JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader);
69 69  
70 70 void talkCmd(Device device, String channelId, MediaServerItem mediaServerItem, String stream, AudioBroadcastEvent event);
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
... ... @@ -1481,7 +1481,7 @@ public class PlayServiceImpl implements IPlayService {
1481 1481 }
1482 1482  
1483 1483 @Override
1484   - public void startSendRtpStreamHand(SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
  1484 + public void startSendRtpStreamHand(SendRtpItem sendRtpItem, Object correlationInfo,
1485 1485 JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader) {
1486 1486 if (jsonObject == null) {
1487 1487 logger.error("RTP推流失败: 请检查ZLM服务");
... ... @@ -1504,10 +1504,13 @@ public class PlayServiceImpl implements IPlayService {
1504 1504 }
1505 1505 } else {
1506 1506 // 向上级平台
1507   - try {
1508   - commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
1509   - } catch (SipException | InvalidArgumentException | ParseException e) {
1510   - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  1507 + if (correlationInfo instanceof ParentPlatform) {
  1508 + try {
  1509 + ParentPlatform parentPlatform = (ParentPlatform)correlationInfo;
  1510 + commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
  1511 + } catch (SipException | InvalidArgumentException | ParseException e) {
  1512 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  1513 + }
1511 1514 }
1512 1515 }
1513 1516 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
... ... @@ -43,6 +43,7 @@ public interface DeviceMapper {
43 43 "on_line," +
44 44 "media_server_id," +
45 45 "switch_primary_sub_stream," +
  46 + "broadcast_push_after_ack," +
46 47 "(SELECT count(0) FROM wvp_device_channel WHERE device_id=wvp_device.device_id) as channel_count "+
47 48 " FROM wvp_device WHERE device_id = #{deviceId}")
48 49 Device getDeviceByDeviceId(String deviceId);
... ... @@ -73,6 +74,7 @@ public interface DeviceMapper {
73 74 "subscribe_cycle_for_alarm,"+
74 75 "ssrc_check,"+
75 76 "as_message_channel,"+
  77 + "broadcast_push_after_ack,"+
76 78 "geo_coord_sys,"+
77 79 "on_line"+
78 80 ") VALUES (" +
... ... @@ -101,6 +103,7 @@ public interface DeviceMapper {
101 103 "#{subscribeCycleForAlarm}," +
102 104 "#{ssrcCheck}," +
103 105 "#{asMessageChannel}," +
  106 + "#{broadcastPushAfterAck}," +
104 107 "#{geoCoordSys}," +
105 108 "#{onLine}" +
106 109 ")")
... ... @@ -155,6 +158,7 @@ public interface DeviceMapper {
155 158 "subscribe_cycle_for_alarm,"+
156 159 "ssrc_check,"+
157 160 "as_message_channel,"+
  161 + "broadcast_push_after_ack,"+
158 162 "geo_coord_sys,"+
159 163 "on_line,"+
160 164 "media_server_id,"+
... ... @@ -196,6 +200,7 @@ public interface DeviceMapper {
196 200 "subscribe_cycle_for_alarm,"+
197 201 "ssrc_check,"+
198 202 "as_message_channel,"+
  203 + "broadcast_push_after_ack,"+
199 204 "geo_coord_sys,"+
200 205 "on_line"+
201 206 " FROM wvp_device WHERE on_line = true")
... ... @@ -226,6 +231,7 @@ public interface DeviceMapper {
226 231 "subscribe_cycle_for_alarm,"+
227 232 "ssrc_check,"+
228 233 "as_message_channel,"+
  234 + "broadcast_push_after_ack,"+
229 235 "geo_coord_sys,"+
230 236 "on_line"+
231 237 " FROM wvp_device WHERE ip = #{host} AND port=#{port}")
... ... @@ -247,6 +253,7 @@ public interface DeviceMapper {
247 253 "<if test=\"subscribeCycleForAlarm != null\">, subscribe_cycle_for_alarm=#{subscribeCycleForAlarm}</if>" +
248 254 "<if test=\"ssrcCheck != null\">, ssrc_check=#{ssrcCheck}</if>" +
249 255 "<if test=\"asMessageChannel != null\">, as_message_channel=#{asMessageChannel}</if>" +
  256 + "<if test=\"broadcastPushAfterAck != null\">, broadcast_push_after_ack=#{broadcastPushAfterAck}</if>" +
250 257 "<if test=\"geoCoordSys != null\">, geo_coord_sys=#{geoCoordSys}</if>" +
251 258 "<if test=\"switchPrimarySubStream != null\">, switch_primary_sub_stream=#{switchPrimarySubStream}</if>" +
252 259 "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" +
... ... @@ -264,6 +271,7 @@ public interface DeviceMapper {
264 271 "charset,"+
265 272 "ssrc_check,"+
266 273 "as_message_channel,"+
  274 + "broadcastPushAfterAck,"+
267 275 "geo_coord_sys,"+
268 276 "on_line,"+
269 277 "media_server_id,"+
... ... @@ -278,6 +286,7 @@ public interface DeviceMapper {
278 286 "#{charset}," +
279 287 "#{ssrcCheck}," +
280 288 "#{asMessageChannel}," +
  289 + "#{broadcastPushAfterAck}," +
281 290 "#{geoCoordSys}," +
282 291 "#{onLine}," +
283 292 "#{mediaServerId}," +
... ...
src/main/resources/local.jks 0 → 100644
No preview for this file type
web_src/src/components/dialog/deviceEdit.vue
... ... @@ -70,6 +70,7 @@
70 70 <el-form-item label="其他选项">
71 71 <el-checkbox label="SSRC校验" v-model="form.ssrcCheck" style="float: left"></el-checkbox>
72 72 <el-checkbox label="作为消息通道" v-model="form.asMessageChannel" style="float: left"></el-checkbox>
  73 + <el-checkbox label="收到ACK后发流" v-model="form.broadcastPushAfterAck" style="float: left"></el-checkbox>
73 74 </el-form-item>
74 75 <el-form-item>
75 76 <div style="float: right;">
... ...