Commit 6fa5b37b962b05b3aa4b7bf019eb47c4cdbb5738

Authored by 648540858
2 parents 4b827f38 16f3b055

Merge branch 'main' into main2

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
#	src/main/resources/all-application.yml
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -69,6 +69,7 @@ public class VideoManagerConstants { @@ -69,6 +69,7 @@ public class VideoManagerConstants {
69 public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; 69 public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_";
70 70
71 public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_"; 71 public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_";
  72 + public static final String BROADCAST_WAITE_INVITE = "task_broadcast_waite_invite_";
72 73
73 74
74 75
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -43,6 +43,8 @@ public class UserSetting { @@ -43,6 +43,8 @@ public class UserSetting {
43 43
44 private Boolean syncChannelOnDeviceOnline = Boolean.FALSE; 44 private Boolean syncChannelOnDeviceOnline = Boolean.FALSE;
45 45
  46 + private Boolean pushStreamAfterAck = Boolean.FALSE;
  47 +
46 private String serverId = "000000"; 48 private String serverId = "000000";
47 49
48 private String thirdPartyGBIdReg = "[\\s\\S]*"; 50 private String thirdPartyGBIdReg = "[\\s\\S]*";
@@ -206,4 +208,12 @@ public class UserSetting { @@ -206,4 +208,12 @@ public class UserSetting {
206 public void setBroadcastForPlatform(String broadcastForPlatform) { 208 public void setBroadcastForPlatform(String broadcastForPlatform) {
207 this.broadcastForPlatform = broadcastForPlatform; 209 this.broadcastForPlatform = broadcastForPlatform;
208 } 210 }
  211 +
  212 + public Boolean getPushStreamAfterAck() {
  213 + return pushStreamAfterAck;
  214 + }
  215 +
  216 + public void setPushStreamAfterAck(Boolean pushStreamAfterAck) {
  217 + this.pushStreamAfterAck = pushStreamAfterAck;
  218 + }
209 } 219 }
src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java
@@ -83,4 +83,19 @@ public class AudioBroadcastManager { @@ -83,4 +83,19 @@ public class AudioBroadcastManager {
83 83
84 return audioBroadcastCatch; 84 return audioBroadcastCatch;
85 } 85 }
  86 +
  87 + public List<AudioBroadcastCatch> get(String deviceId) {
  88 + List<AudioBroadcastCatch> audioBroadcastCatchList= new ArrayList<>();
  89 + if (SipUtils.isFrontEnd(deviceId)) {
  90 + audioBroadcastCatchList.add(data.get(deviceId));
  91 + }else {
  92 + for (String key : data.keySet()) {
  93 + if (key.startsWith(deviceId)) {
  94 + audioBroadcastCatchList.add(data.get(key));
  95 + }
  96 + }
  97 + }
  98 +
  99 + return audioBroadcastCatchList;
  100 + }
86 } 101 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request;
2 2
3 -import com.genersoft.iot.vmp.conf.SipConfig;  
4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 3 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
5 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;  
6 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; 4 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
7 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 5 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
8 -import gov.nist.javax.sip.SipProviderImpl;  
9 import gov.nist.javax.sip.message.SIPRequest; 6 import gov.nist.javax.sip.message.SIPRequest;
10 import gov.nist.javax.sip.message.SIPResponse; 7 import gov.nist.javax.sip.message.SIPResponse;
11 -import gov.nist.javax.sip.stack.SIPServerTransactionImpl;  
12 import org.apache.commons.lang3.ArrayUtils; 8 import org.apache.commons.lang3.ArrayUtils;
13 import org.dom4j.Document; 9 import org.dom4j.Document;
14 import org.dom4j.DocumentException; 10 import org.dom4j.DocumentException;
@@ -17,14 +13,14 @@ import org.dom4j.io.SAXReader; @@ -17,14 +13,14 @@ import org.dom4j.io.SAXReader;
17 import org.slf4j.Logger; 13 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory; 14 import org.slf4j.LoggerFactory;
19 import org.springframework.beans.factory.annotation.Autowired; 15 import org.springframework.beans.factory.annotation.Autowired;
20 -import org.springframework.beans.factory.annotation.Qualifier;  
21 -import org.springframework.security.core.parameters.P;  
22 16
23 import javax.sip.*; 17 import javax.sip.*;
24 import javax.sip.address.Address; 18 import javax.sip.address.Address;
25 import javax.sip.address.AddressFactory; 19 import javax.sip.address.AddressFactory;
26 import javax.sip.address.SipURI; 20 import javax.sip.address.SipURI;
27 -import javax.sip.header.*; 21 +import javax.sip.header.ContentTypeHeader;
  22 +import javax.sip.header.ExpiresHeader;
  23 +import javax.sip.header.HeaderFactory;
28 import javax.sip.message.MessageFactory; 24 import javax.sip.message.MessageFactory;
29 import javax.sip.message.Request; 25 import javax.sip.message.Request;
30 import javax.sip.message.Response; 26 import javax.sip.message.Response;
@@ -157,7 +153,10 @@ public abstract class SIPRequestProcessorParent { @@ -157,7 +153,10 @@ public abstract class SIPRequestProcessorParent {
157 responseAckExtraParam.content = sdp; 153 responseAckExtraParam.content = sdp;
158 responseAckExtraParam.sipURI = sipURI; 154 responseAckExtraParam.sipURI = sipURI;
159 155
160 - return responseAck(request, Response.OK, null, responseAckExtraParam); 156 + SIPResponse sipResponse = responseAck(request, Response.OK, null, responseAckExtraParam);
  157 +
  158 +
  159 + return sipResponse;
161 } 160 }
162 161
163 /** 162 /**
@@ -190,7 +189,8 @@ public abstract class SIPRequestProcessorParent { @@ -190,7 +189,8 @@ public abstract class SIPRequestProcessorParent {
190 reader.setEncoding(charset); 189 reader.setEncoding(charset);
191 // 对海康出现的未转义字符做处理。 190 // 对海康出现的未转义字符做处理。
192 String[] destStrArray = new String[]{"&lt;","&gt;","&amp;","&apos;","&quot;"}; 191 String[] destStrArray = new String[]{"&lt;","&gt;","&amp;","&apos;","&quot;"};
193 - char despChar = '&'; // 或许可扩展兼容其他字符 192 + // 或许可扩展兼容其他字符
  193 + char despChar = '&';
194 byte destBye = (byte) despChar; 194 byte destBye = (byte) despChar;
195 List<Byte> result = new ArrayList<>(); 195 List<Byte> result = new ArrayList<>();
196 byte[] rawContent = request.getRawContent(); 196 byte[] rawContent = request.getRawContent();
@@ -220,4 +220,5 @@ public abstract class SIPRequestProcessorParent { @@ -220,4 +220,5 @@ public abstract class SIPRequestProcessorParent {
220 return xml.getRootElement(); 220 return xml.getRootElement();
221 } 221 }
222 222
  223 +
223 } 224 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2
3 -import com.alibaba.fastjson2.JSON;  
4 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
5 import com.genersoft.iot.vmp.conf.DynamicTask; 4 import com.genersoft.iot.vmp.conf.DynamicTask;
6 -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;  
7 -import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;  
8 -import com.genersoft.iot.vmp.gb28181.bean.Device; 5 +import com.genersoft.iot.vmp.conf.UserSetting;
9 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
10 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 7 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
11 -import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;  
12 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 8 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
13 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;  
14 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;  
15 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; 9 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
16 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 10 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
17 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 11 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
18 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 12 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
19 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 13 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
20 -import com.genersoft.iot.vmp.service.IDeviceService;  
21 import com.genersoft.iot.vmp.service.IMediaServerService; 14 import com.genersoft.iot.vmp.service.IMediaServerService;
  15 +import com.genersoft.iot.vmp.service.IPlayService;
22 import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; 16 import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
23 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; 17 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
24 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 18 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -29,15 +23,15 @@ import org.springframework.beans.factory.InitializingBean; @@ -29,15 +23,15 @@ import org.springframework.beans.factory.InitializingBean;
29 import org.springframework.beans.factory.annotation.Autowired; 23 import org.springframework.beans.factory.annotation.Autowired;
30 import org.springframework.stereotype.Component; 24 import org.springframework.stereotype.Component;
31 25
32 -import javax.sip.InvalidArgumentException;  
33 import javax.sip.RequestEvent; 26 import javax.sip.RequestEvent;
34 -import javax.sip.SipException;  
35 import javax.sip.address.SipURI; 27 import javax.sip.address.SipURI;
36 import javax.sip.header.CallIdHeader; 28 import javax.sip.header.CallIdHeader;
37 import javax.sip.header.FromHeader; 29 import javax.sip.header.FromHeader;
38 import javax.sip.header.HeaderAddress; 30 import javax.sip.header.HeaderAddress;
39 import javax.sip.header.ToHeader; 31 import javax.sip.header.ToHeader;
40 import java.text.ParseException; 32 import java.text.ParseException;
  33 +import java.util.HashMap;
  34 +import java.util.Map;
41 35
42 /** 36 /**
43 * SIP命令类型: ACK请求 37 * SIP命令类型: ACK请求
@@ -46,7 +40,7 @@ import java.text.ParseException; @@ -46,7 +40,7 @@ import java.text.ParseException;
46 @Component 40 @Component
47 public class AckRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor { 41 public class AckRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
48 42
49 - private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class); 43 + private final Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class);
50 private final String method = "ACK"; 44 private final String method = "ACK";
51 45
52 @Autowired 46 @Autowired
@@ -74,31 +68,20 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -74,31 +68,20 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
74 private IMediaServerService mediaServerService; 68 private IMediaServerService mediaServerService;
75 69
76 @Autowired 70 @Autowired
77 - private ZlmHttpHookSubscribe subscribe;  
78 -  
79 - @Autowired  
80 private DynamicTask dynamicTask; 71 private DynamicTask dynamicTask;
81 72
82 @Autowired 73 @Autowired
83 - private ISIPCommander cmder;  
84 -  
85 - @Autowired  
86 - private IDeviceService deviceService;  
87 -  
88 - @Autowired  
89 - private ISIPCommanderForPlatform commanderForPlatform; 74 + private RedisGbPlayMsgListener redisGbPlayMsgListener;
90 75
91 @Autowired 76 @Autowired
92 - private AudioBroadcastManager audioBroadcastManager; 77 + private UserSetting userSetting;
93 78
94 @Autowired 79 @Autowired
95 - private RedisGbPlayMsgListener redisGbPlayMsgListener; 80 + private IPlayService playService;
96 81
97 82
98 /** 83 /**
99 * 处理 ACK请求 84 * 处理 ACK请求
100 - *  
101 - * @param evt  
102 */ 85 */
103 @Override 86 @Override
104 public void process(RequestEvent evt) { 87 public void process(RequestEvent evt) {
@@ -106,44 +89,45 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -106,44 +89,45 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
106 89
107 String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); 90 String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
108 logger.info("[收到ACK]: platformGbId->{}", platformGbId); 91 logger.info("[收到ACK]: platformGbId->{}", platformGbId);
109 - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformGbId);  
110 - // 取消设置的超时任务  
111 - dynamicTask.stop(callIdHeader.getCallId());  
112 - String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();  
113 - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());  
114 - if (sendRtpItem == null) {  
115 - logger.warn("[收到ACK]:未找到通道({})的推流信息", channelId);  
116 - return;  
117 - }  
118 - String is_Udp = sendRtpItem.isTcp() ? "0" : "1";  
119 - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());  
120 - logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStreamId(),  
121 - sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());  
122 - if (mediaInfo == null) {  
123 - RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(  
124 - sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),  
125 - sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),  
126 - sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());  
127 - redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {  
128 - startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, json, callIdHeader);  
129 - });  
130 - }else {  
131 - JSONObject startSendRtpStreamResult = zlmrtpServerFactory.startSendRtp(mediaInfo, sendRtpItem);  
132 - if (startSendRtpStreamResult != null) {  
133 - startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, startSendRtpStreamResult, callIdHeader); 92 + if (userSetting.getPushStreamAfterAck()) {
  93 + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformGbId);
  94 + // 取消设置的超时任务
  95 + dynamicTask.stop(callIdHeader.getCallId());
  96 + String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
  97 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
  98 + if (sendRtpItem == null) {
  99 + logger.warn("[收到ACK]:未找到通道({})的推流信息", channelId);
  100 + return;
  101 + }
  102 + String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
  103 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  104 + logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStreamId(),
  105 + sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
  106 + if (mediaInfo == null) {
  107 + RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
  108 + sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),
  109 + sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
  110 + sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
  111 + redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {
  112 + startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, json, callIdHeader);
  113 + });
  114 + }else {
  115 + JSONObject startSendRtpStreamResult = zlmrtpServerFactory.startSendRtp(mediaInfo, sendRtpItem);
  116 + if (startSendRtpStreamResult != null) {
  117 + startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, startSendRtpStreamResult, callIdHeader);
  118 + }
134 } 119 }
135 } 120 }
136 } 121 }
137 -  
138 private void startSendRtpStreamHand(RequestEvent evt, SendRtpItem sendRtpItem, ParentPlatform parentPlatform, 122 private void startSendRtpStreamHand(RequestEvent evt, SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
139 - JSONObject jsonObject, CallIdHeader callIdHeader) { 123 + JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader) {
140 if (jsonObject == null) { 124 if (jsonObject == null) {
141 logger.error("RTP推流失败: 请检查ZLM服务"); 125 logger.error("RTP推流失败: 请检查ZLM服务");
142 } else if (jsonObject.getInteger("code") == 0) { 126 } else if (jsonObject.getInteger("code") == 0) {
143 logger.info("调用ZLM推流接口, 结果: {}", jsonObject); 127 logger.info("调用ZLM推流接口, 结果: {}", jsonObject);
144 - logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, " ,sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getIp(), sendRtpItem.getPort()); 128 + logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, " ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
145 } else { 129 } else {
146 - logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"), JSON.toJSONString(sendRtpItem)); 130 + logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"), JSON.toJSONString(param));
147 if (sendRtpItem.isOnlyAudio()) { 131 if (sendRtpItem.isOnlyAudio()) {
148 Device device = deviceService.getDevice(sendRtpItem.getDeviceId()); 132 Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
149 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); 133 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
@@ -152,17 +136,12 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -152,17 +136,12 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
152 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null); 136 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null);
153 } catch (SipException | ParseException | InvalidArgumentException | 137 } catch (SipException | ParseException | InvalidArgumentException |
154 SsrcTransactionNotFoundException e) { 138 SsrcTransactionNotFoundException e) {
155 - logger.error("[命令发送失败] 停止语音喊话: {}", e.getMessage()); 139 + logger.error("[命令发送失败] 停止语音对讲: {}", e.getMessage());
156 } 140 }
157 } 141 }
158 - }else {  
159 - // 向上级平台  
160 - try {  
161 - commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());  
162 - } catch (SipException | InvalidArgumentException | ParseException e) {  
163 - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());  
164 - }  
165 } 142 }
166 } 143 }
  144 +
167 } 145 }
  146 +
168 } 147 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
  4 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
4 import com.genersoft.iot.vmp.conf.DynamicTask; 5 import com.genersoft.iot.vmp.conf.DynamicTask;
5 import com.genersoft.iot.vmp.conf.SipConfig; 6 import com.genersoft.iot.vmp.conf.SipConfig;
6 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
@@ -439,18 +440,23 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -439,18 +440,23 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
439 440
440 try { 441 try {
441 // 超时未收到Ack应该回复bye,当前等待时间为10秒 442 // 超时未收到Ack应该回复bye,当前等待时间为10秒
442 - dynamicTask.startDelay(callIdHeader.getCallId(), () -> {  
443 - logger.info("Ack 等待超时");  
444 - mediaServerService.releaseSsrc(mediaServerItemInUSe.getId(), sendRtpItem.getSsrc());  
445 - // 回复bye  
446 - try {  
447 - cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId());  
448 - } catch (SipException | InvalidArgumentException | ParseException e) {  
449 - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());  
450 - }  
451 - }, 60 * 1000);  
452 - responseSdpAck(request, content.toString(), platform); 443 + if (userSetting.getPushStreamAfterAck()) {
  444 + dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
  445 + logger.info("Ack 等待超时");
  446 + mediaServerService.releaseSsrc(mediaServerItemInUSe.getId(), sendRtpItem.getSsrc());
  447 + // 回复bye
  448 + try {
  449 + cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId());
  450 + } catch (SipException | InvalidArgumentException | ParseException e) {
  451 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  452 + }
  453 + }, 60 * 1000);
  454 + }
453 455
  456 + SIPResponse sipResponse = responseSdpAck(request, content.toString(), platform);
  457 + if (!userSetting.getPushStreamAfterAck()) {
  458 + playService.startPushStream(sendRtpItem, sipResponse, platform, request.getCallIdHeader());
  459 + }
454 } catch (SipException e) { 460 } catch (SipException e) {
455 e.printStackTrace(); 461 e.printStackTrace();
456 } catch (InvalidArgumentException e) { 462 } catch (InvalidArgumentException e) {
@@ -878,7 +884,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -878,7 +884,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
878 content.append("f=\r\n"); 884 content.append("f=\r\n");
879 885
880 try { 886 try {
881 - return responseSdpAck(request, content.toString(), platform); 887 + SIPResponse sipResponse = responseSdpAck(request, content.toString(), platform);
  888 + if (!userSetting.getPushStreamAfterAck()) {
  889 + playService.startPushStream(sendRtpItem, sipResponse, platform, request.getCallIdHeader());
  890 + }
  891 + return sipResponse;
882 } catch (SipException e) { 892 } catch (SipException e) {
883 e.printStackTrace(); 893 e.printStackTrace();
884 } catch (InvalidArgumentException e) { 894 } catch (InvalidArgumentException e) {
@@ -905,11 +915,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -905,11 +915,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
905 } 915 }
906 if (device != null) { 916 if (device != null) {
907 logger.info("收到设备" + requesterId + "的语音广播Invite请求"); 917 logger.info("收到设备" + requesterId + "的语音广播Invite请求");
908 - 918 + String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + device.getDeviceId() + audioBroadcastCatch.getChannelId();
  919 + dynamicTask.stop(key);
909 try { 920 try {
910 responseAck(request, Response.TRYING); 921 responseAck(request, Response.TRYING);
911 } catch (SipException | InvalidArgumentException | ParseException e) { 922 } catch (SipException | InvalidArgumentException | ParseException e) {
912 logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage()); 923 logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage());
  924 + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  925 + return;
913 } 926 }
914 String contentString = new String(request.getRawContent()); 927 String contentString = new String(request.getRawContent());
915 // jainSip不支持y=字段, 移除移除以解析。 928 // jainSip不支持y=字段, 移除移除以解析。
@@ -964,11 +977,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -964,11 +977,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
964 responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 977 responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
965 } catch (SipException | InvalidArgumentException | ParseException e) { 978 } catch (SipException | InvalidArgumentException | ParseException e) {
966 logger.error("[命令发送失败] invite 不支持的媒体格式: {}", e.getMessage()); 979 logger.error("[命令发送失败] invite 不支持的媒体格式: {}", e.getMessage());
  980 + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  981 + return;
967 } 982 }
968 return; 983 return;
969 } 984 }
970 String addressStr = sdp.getOrigin().getAddress(); 985 String addressStr = sdp.getOrigin().getAddress();
971 - logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", requesterId, addressStr, port, ssrc); 986 + logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc,
  987 + mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP");
972 988
973 MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device); 989 MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device);
974 if (mediaServerItem == null) { 990 if (mediaServerItem == null) {
@@ -977,6 +993,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -977,6 +993,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
977 responseAck(request, Response.BUSY_HERE); 993 responseAck(request, Response.BUSY_HERE);
978 } catch (SipException | InvalidArgumentException | ParseException e) { 994 } catch (SipException | InvalidArgumentException | ParseException e) {
979 logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage()); 995 logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage());
  996 + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
980 } 997 }
981 return; 998 return;
982 } 999 }
@@ -990,13 +1007,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -990,13 +1007,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
990 responseAck(request, Response.BUSY_HERE); 1007 responseAck(request, Response.BUSY_HERE);
991 } catch (SipException | InvalidArgumentException | ParseException e) { 1008 } catch (SipException | InvalidArgumentException | ParseException e) {
992 logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage()); 1009 logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
  1010 + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  1011 + return;
993 } 1012 }
994 return; 1013 return;
995 } 1014 }
996 - sendRtpItem.setTcp(mediaTransmissionTCP);  
997 - if (tcpActive != null) {  
998 - sendRtpItem.setTcpActive(tcpActive);  
999 - } 1015 +
1000 String app = "broadcast"; 1016 String app = "broadcast";
1001 String stream = device.getDeviceId() + "_" + audioBroadcastCatch.getChannelId(); 1017 String stream = device.getDeviceId() + "_" + audioBroadcastCatch.getChannelId();
1002 1018
@@ -1011,6 +1027,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1011,6 +1027,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1011 sendRtpItem.setUsePs(false); 1027 sendRtpItem.setUsePs(false);
1012 sendRtpItem.setRtcp(false); 1028 sendRtpItem.setRtcp(false);
1013 sendRtpItem.setOnlyAudio(true); 1029 sendRtpItem.setOnlyAudio(true);
  1030 + sendRtpItem.setTcp(mediaTransmissionTCP);
  1031 + if (tcpActive != null) {
  1032 + sendRtpItem.setTcpActive(tcpActive);
  1033 + }
  1034 +
1014 redisCatchStorage.updateSendRTPSever(sendRtpItem); 1035 redisCatchStorage.updateSendRTPSever(sendRtpItem);
1015 1036
1016 1037
@@ -1023,11 +1044,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1023,11 +1044,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1023 responseAck(request, Response.GONE); 1044 responseAck(request, Response.GONE);
1024 } catch (SipException | InvalidArgumentException | ParseException e) { 1045 } catch (SipException | InvalidArgumentException | ParseException e) {
1025 logger.error("[命令发送失败] 语音通话 回复410失败, {}", e.getMessage()); 1046 logger.error("[命令发送失败] 语音通话 回复410失败, {}", e.getMessage());
  1047 + return;
1026 } 1048 }
1027 playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); 1049 playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
1028 } 1050 }
1029 } catch (SdpException e) { 1051 } catch (SdpException e) {
1030 logger.error("[SDP解析异常]", e); 1052 logger.error("[SDP解析异常]", e);
  1053 + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
1031 } 1054 }
1032 } else { 1055 } else {
1033 logger.warn("来自无效设备/平台的请求"); 1056 logger.warn("来自无效设备/平台的请求");
@@ -1084,6 +1107,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1084,6 +1107,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1084 audioBroadcastCatch.setSipTransactionInfoByRequset(sipResponse); 1107 audioBroadcastCatch.setSipTransactionInfoByRequset(sipResponse);
1085 audioBroadcastManager.update(audioBroadcastCatch); 1108 audioBroadcastManager.update(audioBroadcastCatch);
1086 1109
  1110 + // 开启发流,大华在收到200OK后就会开始建立连接
  1111 + if (!userSetting.getPushStreamAfterAck()) {
  1112 + playService.startPushStream(sendRtpItem, sipResponse, parentPlatform, request.getCallIdHeader());
  1113 + }
  1114 +
1087 } catch (SipException | InvalidArgumentException | ParseException | SdpParseException e) { 1115 } catch (SipException | InvalidArgumentException | ParseException | SdpParseException e) {
1088 logger.error("[命令发送失败] 语音喊话 回复200OK(SDP): {}", e.getMessage()); 1116 logger.error("[命令发送失败] 语音喊话 回复200OK(SDP): {}", e.getMessage());
1089 } 1117 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
2 2
  3 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  4 +import com.genersoft.iot.vmp.conf.DynamicTask;
3 import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch; 5 import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
4 import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatchStatus; 6 import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatchStatus;
5 import com.genersoft.iot.vmp.gb28181.bean.Device; 7 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -9,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; @@ -9,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
9 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
10 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; 12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; 13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
  14 +import com.genersoft.iot.vmp.service.IPlayService;
12 import gov.nist.javax.sip.message.SIPRequest; 15 import gov.nist.javax.sip.message.SIPRequest;
13 import org.dom4j.Element; 16 import org.dom4j.Element;
14 import org.slf4j.Logger; 17 import org.slf4j.Logger;
@@ -35,11 +38,14 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i @@ -35,11 +38,14 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i
35 private ResponseMessageHandler responseMessageHandler; 38 private ResponseMessageHandler responseMessageHandler;
36 39
37 @Autowired 40 @Autowired
38 - private DeferredResultHolder deferredResultHolder; 41 + private DynamicTask dynamicTask;
39 42
40 @Autowired 43 @Autowired
41 private AudioBroadcastManager audioBroadcastManager; 44 private AudioBroadcastManager audioBroadcastManager;
42 45
  46 + @Autowired
  47 + private IPlayService playService;
  48 +
43 @Override 49 @Override
44 public void afterPropertiesSet() throws Exception { 50 public void afterPropertiesSet() throws Exception {
45 responseMessageHandler.addHandler(cmdType, this); 51 responseMessageHandler.addHandler(cmdType, this);
@@ -47,6 +53,8 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i @@ -47,6 +53,8 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i
47 53
48 @Override 54 @Override
49 public void handForDevice(RequestEvent evt, Device device, Element rootElement) { 55 public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
  56 +
  57 + SIPRequest request = (SIPRequest) evt.getRequest();
50 try { 58 try {
51 String channelId = getText(rootElement, "DeviceID"); 59 String channelId = getText(rootElement, "DeviceID");
52 if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) { 60 if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
@@ -55,12 +63,23 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i @@ -55,12 +63,23 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i
55 return; 63 return;
56 } 64 }
57 String result = getText(rootElement, "Result"); 65 String result = getText(rootElement, "Result");
58 - logger.info("收到语音广播的回复 {}:{}/{}", result, device.getDeviceId(), channelId );  
59 - AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), channelId);  
60 - audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.WaiteInvite);  
61 - audioBroadcastManager.update(audioBroadcastCatch); 66 + logger.info("[语音广播]回复:{}, {}/{}", result, device.getDeviceId(), channelId );
  67 +
62 // 回复200 OK 68 // 回复200 OK
63 - responseAck((SIPRequest) evt.getRequest(), Response.OK); 69 + responseAck(request, Response.OK);
  70 + if (result.equalsIgnoreCase("OK")) {
  71 + AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), channelId);
  72 + audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.WaiteInvite);
  73 + audioBroadcastManager.update(audioBroadcastCatch);
  74 + // 等待invite消息, 超时则结束
  75 + String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + device.getDeviceId() + channelId;
  76 + dynamicTask.startDelay(key, ()->{
  77 + logger.info("[语音广播]等待invite消息超时:{}/{}", device.getDeviceId(), channelId);
  78 + playService.stopAudioBroadcast(device.getDeviceId(), channelId);
  79 + }, 2000);
  80 + }else {
  81 + playService.stopAudioBroadcast(device.getDeviceId(), channelId);
  82 + }
64 } catch (ParseException | SipException | InvalidArgumentException e) { 83 } catch (ParseException | SipException | InvalidArgumentException e) {
65 logger.error("[命令发送失败] 国标级联 语音喊话: {}", e.getMessage()); 84 logger.error("[命令发送失败] 国标级联 语音喊话: {}", e.getMessage());
66 } 85 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
@@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; @@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
35 public class CatalogResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { 35 public class CatalogResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
36 36
37 private Logger logger = LoggerFactory.getLogger(CatalogResponseMessageHandler.class); 37 private Logger logger = LoggerFactory.getLogger(CatalogResponseMessageHandler.class);
  38 +
38 private final String cmdType = "Catalog"; 39 private final String cmdType = "Catalog";
39 40
40 @Autowired 41 @Autowired
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -323,7 +323,7 @@ public class ZLMHttpHookListener { @@ -323,7 +323,7 @@ public class ZLMHttpHookListener {
323 }); 323 });
324 324
325 if ("rtsp".equals(param.getSchema())){ 325 if ("rtsp".equals(param.getSchema())){
326 - logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", param.isRegist(), param.getApp(), param.getStream()); 326 + logger.info("流变化:注册->{}, app->{}, stream->{}", param.isRegist(), param.getApp(), param.getStream());
327 if (param.isRegist()) { 327 if (param.isRegist()) {
328 mediaServerService.addCount(param.getMediaServerId()); 328 mediaServerService.addCount(param.getMediaServerId());
329 }else { 329 }else {
@@ -383,10 +383,10 @@ public class ZLMHttpHookListener { @@ -383,10 +383,10 @@ public class ZLMHttpHookListener {
383 } 383 }
384 384
385 }else { 385 }else {
386 - logger.info("[语音喊话] 推流指向的·通道{}未找到", channelId); 386 + logger.info("[语音对讲] 未找到通道:{}", channelId);
387 } 387 }
388 - }else {  
389 - logger.info("[语音喊话] 推流指向的·设备{}未找到", deviceId); 388 + }else{
  389 + logger.info("[语音对讲] 未找到设备:{}", deviceId);
390 } 390 }
391 }else { 391 }else {
392 logger.info("[语音喊话] 推流格式有误, 格式为: broadcast/设备编号_通道编号 "); 392 logger.info("[语音喊话] 推流格式有误, 格式为: broadcast/设备编号_通道编号 ");
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -36,7 +36,7 @@ public class ZLMRESTfulUtils { @@ -36,7 +36,7 @@ public class ZLMRESTfulUtils {
36 // 设置连接超时时间 36 // 设置连接超时时间
37 httpClientBuilder.connectTimeout(5,TimeUnit.SECONDS); 37 httpClientBuilder.connectTimeout(5,TimeUnit.SECONDS);
38 // 设置读取超时时间 38 // 设置读取超时时间
39 - httpClientBuilder.readTimeout(5,TimeUnit.SECONDS); 39 + httpClientBuilder.readTimeout(15,TimeUnit.SECONDS);
40 // 设置连接池 40 // 设置连接池
41 httpClientBuilder.connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES)); 41 httpClientBuilder.connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES));
42 if (logger.isDebugEnabled()) { 42 if (logger.isDebugEnabled()) {
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -3,9 +3,7 @@ package com.genersoft.iot.vmp.service; @@ -3,9 +3,7 @@ package com.genersoft.iot.vmp.service;
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
4 import com.genersoft.iot.vmp.common.StreamInfo; 4 import com.genersoft.iot.vmp.common.StreamInfo;
5 import com.genersoft.iot.vmp.conf.exception.ServiceException; 5 import com.genersoft.iot.vmp.conf.exception.ServiceException;
6 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
7 -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;  
8 -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; 6 +import com.genersoft.iot.vmp.gb28181.bean.*;
9 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 7 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
10 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 8 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 9 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -15,11 +13,14 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; @@ -15,11 +13,14 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo;
15 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; 13 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
16 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; 14 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
17 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 15 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
  16 +import gov.nist.javax.sip.message.SIPResponse;
18 import org.springframework.web.context.request.async.DeferredResult; 17 import org.springframework.web.context.request.async.DeferredResult;
19 18
20 import javax.sip.InvalidArgumentException; 19 import javax.sip.InvalidArgumentException;
21 import javax.sip.SipException; 20 import javax.sip.SipException;
  21 +import javax.sip.header.CallIdHeader;
22 import java.text.ParseException; 22 import java.text.ParseException;
  23 +import java.util.Map;
23 24
24 /** 25 /**
25 * 点播处理 26 * 点播处理
@@ -64,4 +65,9 @@ public interface IPlayService { @@ -64,4 +65,9 @@ public interface IPlayService {
64 void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException; 65 void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
65 66
66 void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException; 67 void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
  68 +
  69 + void startPushStream(SendRtpItem sendRtpItem, SIPResponse sipResponse, ParentPlatform platform, CallIdHeader callIdHeader);
  70 +
  71 + void startSendRtpStreamHand(SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
  72 + JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader);
67 } 73 }
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -3,12 +3,15 @@ package com.genersoft.iot.vmp.service.impl; @@ -3,12 +3,15 @@ package com.genersoft.iot.vmp.service.impl;
3 import com.genersoft.iot.vmp.conf.DynamicTask; 3 import com.genersoft.iot.vmp.conf.DynamicTask;
4 import com.genersoft.iot.vmp.conf.UserSetting; 4 import com.genersoft.iot.vmp.conf.UserSetting;
5 import com.genersoft.iot.vmp.gb28181.bean.*; 5 import com.genersoft.iot.vmp.gb28181.bean.*;
  6 +import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
6 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 7 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
7 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; 8 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
8 import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; 9 import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
9 import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; 10 import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler; 12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;
  13 +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  14 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 import com.genersoft.iot.vmp.service.IDeviceChannelService; 15 import com.genersoft.iot.vmp.service.IDeviceChannelService;
13 import com.genersoft.iot.vmp.service.IDeviceService; 16 import com.genersoft.iot.vmp.service.IDeviceService;
14 import com.genersoft.iot.vmp.service.IMediaServerService; 17 import com.genersoft.iot.vmp.service.IMediaServerService;
@@ -32,9 +35,7 @@ import javax.sip.InvalidArgumentException; @@ -32,9 +35,7 @@ import javax.sip.InvalidArgumentException;
32 import javax.sip.SipException; 35 import javax.sip.SipException;
33 import java.text.ParseException; 36 import java.text.ParseException;
34 import java.time.Instant; 37 import java.time.Instant;
35 -import java.util.ArrayList;  
36 -import java.util.Collections;  
37 -import java.util.List; 38 +import java.util.*;
38 import java.util.concurrent.TimeUnit; 39 import java.util.concurrent.TimeUnit;
39 40
40 /** 41 /**
@@ -89,6 +90,12 @@ public class DeviceServiceImpl implements IDeviceService { @@ -89,6 +90,12 @@ public class DeviceServiceImpl implements IDeviceService {
89 @Autowired 90 @Autowired
90 private IMediaServerService mediaServerService; 91 private IMediaServerService mediaServerService;
91 92
  93 + @Autowired
  94 + private AudioBroadcastManager audioBroadcastManager;
  95 +
  96 + @Autowired
  97 + private ZLMRESTfulUtils zlmresTfulUtils;
  98 +
92 @Override 99 @Override
93 public void online(Device device) { 100 public void online(Device device) {
94 logger.info("[设备上线] deviceId:{}->{}:{}", device.getDeviceId(), device.getIp(), device.getPort()); 101 logger.info("[设备上线] deviceId:{}->{}:{}", device.getDeviceId(), device.getIp(), device.getPort());
@@ -183,6 +190,23 @@ public class DeviceServiceImpl implements IDeviceService { @@ -183,6 +190,23 @@ public class DeviceServiceImpl implements IDeviceService {
183 // 移除订阅 190 // 移除订阅
184 removeCatalogSubscribe(device); 191 removeCatalogSubscribe(device);
185 removeMobilePositionSubscribe(device); 192 removeMobilePositionSubscribe(device);
  193 + List<AudioBroadcastCatch> audioBroadcastCatches = audioBroadcastManager.get(deviceId);
  194 + if (audioBroadcastCatches.size() > 0) {
  195 + for (AudioBroadcastCatch audioBroadcastCatch : audioBroadcastCatches) {
  196 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null);
  197 + if (sendRtpItem != null) {
  198 + redisCatchStorage.deleteSendRTPServer(deviceId, sendRtpItem.getChannelId(), null, null);
  199 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  200 + Map<String, Object> param = new HashMap<>();
  201 + param.put("vhost", "__defaultVhost__");
  202 + param.put("app", sendRtpItem.getApp());
  203 + param.put("stream", sendRtpItem.getStreamId());
  204 + zlmresTfulUtils.stopSendRtp(mediaInfo, param);
  205 + }
  206 +
  207 + audioBroadcastManager.del(deviceId, audioBroadcastCatch.getChannelId());
  208 + }
  209 + }
186 } 210 }
187 211
188 @Override 212 @Override
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -24,16 +24,15 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; @@ -24,16 +24,15 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
24 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 24 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
25 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 25 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
26 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; 26 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  27 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
27 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; 28 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
28 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 29 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
29 import com.genersoft.iot.vmp.service.IDeviceService; 30 import com.genersoft.iot.vmp.service.IDeviceService;
30 import com.genersoft.iot.vmp.service.IMediaServerService; 31 import com.genersoft.iot.vmp.service.IMediaServerService;
31 import com.genersoft.iot.vmp.service.IMediaService; 32 import com.genersoft.iot.vmp.service.IMediaService;
32 import com.genersoft.iot.vmp.service.IPlayService; 33 import com.genersoft.iot.vmp.service.IPlayService;
33 -import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;  
34 -import com.genersoft.iot.vmp.service.bean.PlayBackCallback;  
35 -import com.genersoft.iot.vmp.service.bean.PlayBackResult;  
36 -import com.genersoft.iot.vmp.service.bean.SSRCInfo; 34 +import com.genersoft.iot.vmp.service.bean.*;
  35 +import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
37 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 36 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
38 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 37 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
39 import com.genersoft.iot.vmp.utils.DateUtil; 38 import com.genersoft.iot.vmp.utils.DateUtil;
@@ -42,6 +41,7 @@ import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; @@ -42,6 +41,7 @@ import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
42 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 41 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
43 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 42 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
44 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; 43 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
  44 +import gov.nist.javax.sip.message.SIPResponse;
45 import org.slf4j.Logger; 45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory; 46 import org.slf4j.LoggerFactory;
47 import org.springframework.beans.factory.annotation.Autowired; 47 import org.springframework.beans.factory.annotation.Autowired;
@@ -54,13 +54,11 @@ import org.springframework.web.context.request.async.DeferredResult; @@ -54,13 +54,11 @@ import org.springframework.web.context.request.async.DeferredResult;
54 import javax.sip.InvalidArgumentException; 54 import javax.sip.InvalidArgumentException;
55 import javax.sip.ResponseEvent; 55 import javax.sip.ResponseEvent;
56 import javax.sip.SipException; 56 import javax.sip.SipException;
  57 +import javax.sip.header.CallIdHeader;
57 import java.math.BigDecimal; 58 import java.math.BigDecimal;
58 import java.math.RoundingMode; 59 import java.math.RoundingMode;
59 import java.text.ParseException; 60 import java.text.ParseException;
60 -import java.util.HashMap;  
61 -import java.util.List;  
62 -import java.util.Map;  
63 -import java.util.UUID; 61 +import java.util.*;
64 62
65 @SuppressWarnings(value = {"rawtypes", "unchecked"}) 63 @SuppressWarnings(value = {"rawtypes", "unchecked"})
66 @Service 64 @Service
@@ -119,11 +117,20 @@ public class PlayServiceImpl implements IPlayService { @@ -119,11 +117,20 @@ public class PlayServiceImpl implements IPlayService {
119 @Autowired 117 @Autowired
120 private ZlmHttpHookSubscribe subscribe; 118 private ZlmHttpHookSubscribe subscribe;
121 119
  120 + @Autowired
  121 + private ISIPCommanderForPlatform commanderForPlatform;
  122 +
122 123
123 @Qualifier("taskExecutor") 124 @Qualifier("taskExecutor")
124 @Autowired 125 @Autowired
125 private ThreadPoolTaskExecutor taskExecutor; 126 private ThreadPoolTaskExecutor taskExecutor;
126 127
  128 + @Autowired
  129 + private RedisGbPlayMsgListener redisGbPlayMsgListener;
  130 +
  131 + @Autowired
  132 + private ZlmHttpHookSubscribe hookSubscribe;
  133 +
127 134
128 @Override 135 @Override
129 public void play(MediaServerItem mediaServerItem, String deviceId, String channelId, 136 public void play(MediaServerItem mediaServerItem, String deviceId, String channelId,
@@ -1024,8 +1031,20 @@ public class PlayServiceImpl implements IPlayService { @@ -1024,8 +1031,20 @@ public class PlayServiceImpl implements IPlayService {
1024 return false; 1031 return false;
1025 } 1032 }
1026 // 查询通道使用状态 1033 // 查询通道使用状态
1027 - if (audioBroadcastInUse(device, channelId)) {  
1028 - return false; 1034 + if (audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
  1035 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
  1036 + if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) {
  1037 + // 查询流是否存在,不存在则认为是异常状态
  1038 + MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  1039 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, sendRtpItem.getApp(), sendRtpItem.getStreamId());
  1040 + if (streamReady) {
  1041 + logger.warn("语音广播已经开启: {}", channelId);
  1042 + event.call("语音广播已经开启");
  1043 + return;
  1044 + } else {
  1045 + stopAudioBroadcast(device.getDeviceId(), channelId);
  1046 + }
  1047 + }
1029 } 1048 }
1030 1049
1031 // 发送通知 1050 // 发送通知
@@ -1063,28 +1082,31 @@ public class PlayServiceImpl implements IPlayService { @@ -1063,28 +1082,31 @@ public class PlayServiceImpl implements IPlayService {
1063 1082
1064 @Override 1083 @Override
1065 public void stopAudioBroadcast(String deviceId, String channelId) { 1084 public void stopAudioBroadcast(String deviceId, String channelId) {
1066 - AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(deviceId, channelId);  
1067 - if (audioBroadcastCatch != null) { 1085 + List<AudioBroadcastCatch> audioBroadcastCatchList = new ArrayList<>();
  1086 + if (channelId == null) {
  1087 + audioBroadcastCatchList.addAll(audioBroadcastManager.get(deviceId));
  1088 + }else {
  1089 + audioBroadcastCatchList.add(audioBroadcastManager.get(deviceId, channelId));
  1090 + }
  1091 + if (audioBroadcastCatchList.size() > 0) {
  1092 + for (AudioBroadcastCatch audioBroadcastCatch : audioBroadcastCatchList) {
  1093 + Device device = deviceService.getDevice(deviceId);
  1094 + if (device == null || audioBroadcastCatch == null ) {
  1095 + return;
  1096 + }
  1097 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null);
  1098 + if (sendRtpItem != null) {
  1099 + redisCatchStorage.deleteSendRTPServer(deviceId, sendRtpItem.getChannelId(), null, null);
  1100 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  1101 + Map<String, Object> param = new HashMap<>();
  1102 + param.put("vhost", "__defaultVhost__");
  1103 + param.put("app", sendRtpItem.getApp());
  1104 + param.put("stream", sendRtpItem.getStreamId());
  1105 + zlmresTfulUtils.stopSendRtp(mediaInfo, param);
  1106 + }
1068 1107
1069 - Device device = deviceService.getDevice(deviceId);  
1070 - if (device == null) {  
1071 - return;  
1072 - }  
1073 - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null);  
1074 - if (sendRtpItem != null) {  
1075 - redisCatchStorage.deleteSendRTPServer(deviceId, sendRtpItem.getChannelId(), null, null);  
1076 - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());  
1077 - Map<String, Object> param = new HashMap<>();  
1078 - param.put("vhost", "__defaultVhost__");  
1079 - param.put("app", sendRtpItem.getApp());  
1080 - param.put("stream", sendRtpItem.getStreamId());  
1081 - zlmresTfulUtils.stopSendRtp(mediaInfo, param);  
1082 - }  
1083 - if (audioBroadcastCatch.isFromPlatform()) {  
1084 - // TODO 向上级发送BYE结束语音喊话 1108 + audioBroadcastManager.del(deviceId, channelId);
1085 } 1109 }
1086 -  
1087 - audioBroadcastManager.del(deviceId, channelId);  
1088 } 1110 }
1089 } 1111 }
1090 1112
@@ -1187,4 +1209,100 @@ public class PlayServiceImpl implements IPlayService { @@ -1187,4 +1209,100 @@ public class PlayServiceImpl implements IPlayService {
1187 Device device = storager.queryVideoDevice(streamInfo.getDeviceID()); 1209 Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
1188 cmder.playResumeCmd(device, streamInfo); 1210 cmder.playResumeCmd(device, streamInfo);
1189 } 1211 }
  1212 +
  1213 + @Override
  1214 + public void startPushStream(SendRtpItem sendRtpItem, SIPResponse sipResponse, ParentPlatform platform, CallIdHeader callIdHeader) {
  1215 +
  1216 + // 开始发流
  1217 + // 取消设置的超时任务
  1218 +// String channelId = request.getCallIdHeader().getCallId();
  1219 +
  1220 + String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
  1221 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  1222 + logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStreamId(),
  1223 + sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
  1224 + Map<String, Object> param = new HashMap<>(12);
  1225 + param.put("vhost","__defaultVhost__");
  1226 + param.put("app",sendRtpItem.getApp());
  1227 + param.put("stream",sendRtpItem.getStreamId());
  1228 + param.put("ssrc", sendRtpItem.getSsrc());
  1229 + param.put("src_port", sendRtpItem.getLocalPort());
  1230 + param.put("pt", sendRtpItem.getPt());
  1231 + param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  1232 + param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  1233 + param.put("is_udp", is_Udp);
  1234 + if (!sendRtpItem.isTcp()) {
  1235 + // udp模式下开启rtcp保活
  1236 + param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
  1237 + }
  1238 +
  1239 + if (mediaInfo == null) {
  1240 + RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
  1241 + sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),
  1242 + sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
  1243 + sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
  1244 + redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {
  1245 + startSendRtpStreamHand(sendRtpItem, platform, json, param, callIdHeader);
  1246 + });
  1247 + } else {
  1248 + // 如果是非严格模式,需要关闭端口占用
  1249 + JSONObject startSendRtpStreamResult = null;
  1250 + if (sendRtpItem.getLocalPort() != 0) {
  1251 + HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(sendRtpItem.getSsrc(), null, mediaInfo.getId());
  1252 + hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
  1253 + if (zlmrtpServerFactory.releasePort(mediaInfo, sendRtpItem.getSsrc())) {
  1254 + if (sendRtpItem.isTcpActive()) {
  1255 + startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
  1256 + }else {
  1257 + param.put("dst_url", sendRtpItem.getIp());
  1258 + param.put("dst_port", sendRtpItem.getPort());
  1259 + startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  1260 + }
  1261 + }
  1262 + }else {
  1263 + if (sendRtpItem.isTcpActive()) {
  1264 + startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
  1265 + }else {
  1266 + param.put("dst_url", sendRtpItem.getIp());
  1267 + param.put("dst_port", sendRtpItem.getPort());
  1268 + startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  1269 + }
  1270 + }
  1271 + if (startSendRtpStreamResult != null) {
  1272 + startSendRtpStreamHand(sendRtpItem, platform, startSendRtpStreamResult, param, callIdHeader);
  1273 + }
  1274 + }
  1275 + }
  1276 +
  1277 + @Override
  1278 + public void startSendRtpStreamHand(SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
  1279 + JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader) {
  1280 + if (jsonObject == null) {
  1281 + logger.error("RTP推流失败: 请检查ZLM服务");
  1282 + } else if (jsonObject.getInteger("code") == 0) {
  1283 + logger.info("调用ZLM推流接口, 结果: {}", jsonObject);
  1284 + logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, " ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
  1285 + } else {
  1286 + logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"), JSON.toJSONString(param));
  1287 + if (sendRtpItem.isOnlyAudio()) {
  1288 + Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
  1289 + AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
  1290 + if (audioBroadcastCatch != null) {
  1291 + try {
  1292 + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null);
  1293 + } catch (SipException | ParseException | InvalidArgumentException |
  1294 + SsrcTransactionNotFoundException e) {
  1295 + logger.error("[命令发送失败] 停止语音对讲: {}", e.getMessage());
  1296 + }
  1297 + }
  1298 + }else {
  1299 + // 向上级平台
  1300 + try {
  1301 + commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
  1302 + } catch (SipException | InvalidArgumentException | ParseException e) {
  1303 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  1304 + }
  1305 + }
  1306 + }
  1307 + }
1190 } 1308 }
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -6,7 +6,6 @@ import com.genersoft.iot.vmp.gb28181.bean.*; @@ -6,7 +6,6 @@ import com.genersoft.iot.vmp.gb28181.bean.*;
6 import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 6 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
7 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; 7 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
8 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; 8 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
9 -import com.genersoft.iot.vmp.service.IGbStreamService;  
10 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; 9 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
11 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 10 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
12 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 11 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
@@ -90,12 +89,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -90,12 +89,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
90 @Autowired 89 @Autowired
91 private PlatformGbStreamMapper platformGbStreamMapper; 90 private PlatformGbStreamMapper platformGbStreamMapper;
92 91
93 - @Autowired  
94 - private IGbStreamService gbStreamService;  
95 -  
96 - @Autowired  
97 - private ParentPlatformMapper parentPlatformMapper;  
98 -  
99 /** 92 /**
100 * 根据设备ID判断设备是否存在 93 * 根据设备ID判断设备是否存在
101 * 94 *
src/main/resources/all-application.yml
@@ -197,6 +197,8 @@ user-settings: @@ -197,6 +197,8 @@ user-settings:
197 sync-channel-on-device-online: false 197 sync-channel-on-device-online: false
198 # 国标级联语音喊话发流模式 * UDP:udp传输 TCP-ACTIVE:tcp主动模式 TCP-PASSIVE:tcp被动模式 198 # 国标级联语音喊话发流模式 * UDP:udp传输 TCP-ACTIVE:tcp主动模式 TCP-PASSIVE:tcp被动模式
199 broadcast-for-platform: UDP 199 broadcast-for-platform: UDP
  200 + # 收到ack消息后开始发流,默认false, 回复200ok后直接开始发流
  201 + push-stream-after-ack: false
200 202
201 # 关闭在线文档(生产环境建议关闭) 203 # 关闭在线文档(生产环境建议关闭)
202 springdoc: 204 springdoc: