Commit 988dc36fa56a47cc4f331ab48c07577805a71425

Authored by 648540858
1 parent ba884fa9

重构点播,回放,下载时ssrc不一致以及TCP主动播放的逻辑

src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
@@ -46,6 +46,9 @@ public class DynamicTask { @@ -46,6 +46,9 @@ public class DynamicTask {
46 * @return 46 * @return
47 */ 47 */
48 public void startCron(String key, Runnable task, int cycleForCatalog) { 48 public void startCron(String key, Runnable task, int cycleForCatalog) {
  49 + if(ObjectUtils.isEmpty(key)) {
  50 + return;
  51 + }
49 ScheduledFuture<?> future = futureMap.get(key); 52 ScheduledFuture<?> future = futureMap.get(key);
50 if (future != null) { 53 if (future != null) {
51 if (future.isCancelled()) { 54 if (future.isCancelled()) {
@@ -74,6 +77,9 @@ public class DynamicTask { @@ -74,6 +77,9 @@ public class DynamicTask {
74 * @return 77 * @return
75 */ 78 */
76 public void startDelay(String key, Runnable task, int delay) { 79 public void startDelay(String key, Runnable task, int delay) {
  80 + if(ObjectUtils.isEmpty(key)) {
  81 + return;
  82 + }
77 stop(key); 83 stop(key);
78 84
79 // 获取执行的时刻 85 // 获取执行的时刻
@@ -100,9 +106,12 @@ public class DynamicTask { @@ -100,9 +106,12 @@ public class DynamicTask {
100 } 106 }
101 107
102 public boolean stop(String key) { 108 public boolean stop(String key) {
  109 + if(ObjectUtils.isEmpty(key)) {
  110 + return false;
  111 + }
103 boolean result = false; 112 boolean result = false;
104 if (!ObjectUtils.isEmpty(futureMap.get(key)) && !futureMap.get(key).isCancelled() && !futureMap.get(key).isDone()) { 113 if (!ObjectUtils.isEmpty(futureMap.get(key)) && !futureMap.get(key).isCancelled() && !futureMap.get(key).isDone()) {
105 - result = futureMap.get(key).cancel(false); 114 + result = futureMap.get(key).cancel(true);
106 futureMap.remove(key); 115 futureMap.remove(key);
107 runnableMap.remove(key); 116 runnableMap.remove(key);
108 } 117 }
@@ -110,6 +119,9 @@ public class DynamicTask { @@ -110,6 +119,9 @@ public class DynamicTask {
110 } 119 }
111 120
112 public boolean contains(String key) { 121 public boolean contains(String key) {
  122 + if(ObjectUtils.isEmpty(key)) {
  123 + return false;
  124 + }
113 return futureMap.get(key) != null; 125 return futureMap.get(key) != null;
114 } 126 }
115 127
@@ -118,6 +130,9 @@ public class DynamicTask { @@ -118,6 +130,9 @@ public class DynamicTask {
118 } 130 }
119 131
120 public Runnable get(String key) { 132 public Runnable get(String key) {
  133 + if(ObjectUtils.isEmpty(key)) {
  134 + return null;
  135 + }
121 return runnableMap.get(key); 136 return runnableMap.get(key);
122 } 137 }
123 138
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
@@ -138,7 +138,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -138,7 +138,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
138 logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId); 138 logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId);
139 } 139 }
140 try { 140 try {
141 - logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); 141 + logger.info("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
142 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null); 142 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null);
143 } catch (InvalidArgumentException | ParseException | SipException | 143 } catch (InvalidArgumentException | ParseException | SipException |
144 SsrcTransactionNotFoundException e) { 144 SsrcTransactionNotFoundException e) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -33,7 +33,7 @@ import java.text.ParseException; @@ -33,7 +33,7 @@ import java.text.ParseException;
33 public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { 33 public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
34 34
35 35
36 - private Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class); 36 + private final Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class);
37 private final static String cmdType = "Keepalive"; 37 private final static String cmdType = "Keepalive";
38 38
39 @Autowired 39 @Autowired
@@ -59,14 +59,19 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp @@ -59,14 +59,19 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
59 // 未注册的设备不做处理 59 // 未注册的设备不做处理
60 return; 60 return;
61 } 61 }
62 - logger.info("[收到心跳], device: {}", device.getDeviceId());  
63 SIPRequest request = (SIPRequest) evt.getRequest(); 62 SIPRequest request = (SIPRequest) evt.getRequest();
  63 + logger.info("[收到心跳], device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId());
  64 +
64 // 回复200 OK 65 // 回复200 OK
65 try { 66 try {
66 responseAck(request, Response.OK); 67 responseAck(request, Response.OK);
67 } catch (SipException | InvalidArgumentException | ParseException e) { 68 } catch (SipException | InvalidArgumentException | ParseException e) {
68 logger.error("[命令发送失败] 心跳回复: {}", e.getMessage()); 69 logger.error("[命令发送失败] 心跳回复: {}", e.getMessage());
69 } 70 }
  71 + if (DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L){
  72 + logger.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId());
  73 + return;
  74 + }
70 75
71 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); 76 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress());
72 if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { 77 if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) {
@@ -80,7 +85,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp @@ -80,7 +85,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
80 }else { 85 }else {
81 long lastTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(device.getKeepaliveTime()); 86 long lastTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(device.getKeepaliveTime());
82 if (System.currentTimeMillis()/1000-lastTime > 10) { 87 if (System.currentTimeMillis()/1000-lastTime > 10) {
83 - device.setKeepaliveIntervalTime(new Long(System.currentTimeMillis()/1000-lastTime).intValue()); 88 + device.setKeepaliveIntervalTime(Long.valueOf(System.currentTimeMillis()/1000-lastTime).intValue());
84 } 89 }
85 } 90 }
86 91
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -494,6 +494,7 @@ public class ZLMHttpHookListener { @@ -494,6 +494,7 @@ public class ZLMHttpHookListener {
494 Device device = deviceService.getDevice(inviteInfo.getDeviceId()); 494 Device device = deviceService.getDevice(inviteInfo.getDeviceId());
495 if (device != null) { 495 if (device != null) {
496 try { 496 try {
  497 + // 多查询一次防止已经被处理了
497 InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(), 498 InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),
498 inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()); 499 inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
499 if (info != null) { 500 if (info != null) {
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
@@ -98,6 +98,9 @@ public class InviteStreamServiceImpl implements IInviteStreamService { @@ -98,6 +98,9 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
98 "_" + inviteInfo.getChannelId() + 98 "_" + inviteInfo.getChannelId() +
99 "_" + stream; 99 "_" + stream;
100 inviteInfoInDb.setStream(stream); 100 inviteInfoInDb.setStream(stream);
  101 + if (inviteInfoInDb.getSsrcInfo() != null) {
  102 + inviteInfoInDb.getSsrcInfo().setStream(stream);
  103 + }
101 redisTemplate.opsForValue().set(key, inviteInfoInDb); 104 redisTemplate.opsForValue().set(key, inviteInfoInDb);
102 return inviteInfoInDb; 105 return inviteInfoInDb;
103 } 106 }
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -151,9 +151,14 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -151,9 +151,14 @@ public class MediaServerServiceImpl implements IMediaServerService {
151 if (streamId == null) { 151 if (streamId == null) {
152 streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); 152 streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
153 } 153 }
  154 + int ssrcCheckParam = 0;
  155 + if (ssrcCheck && tcpMode > 1) {
  156 + // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验
  157 + logger.warn("[openRTPServer] TCP被动/TCP主动收流时,默认关闭ssrc检验");
  158 + }
154 int rtpServerPort; 159 int rtpServerPort;
155 if (mediaServerItem.isRtpEnable()) { 160 if (mediaServerItem.isRtpEnable()) {
156 - rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port, reUsePort, tcpMode); 161 + rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0)?Integer.parseInt(ssrc):0, port, reUsePort, tcpMode);
157 } else { 162 } else {
158 rtpServerPort = mediaServerItem.getRtpProxyPort(); 163 rtpServerPort = mediaServerItem.getRtpProxyPort();
159 } 164 }
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -17,6 +17,7 @@ import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; @@ -17,6 +17,7 @@ import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
17 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 17 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
18 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 18 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
19 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 19 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
  20 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
20 import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; 21 import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
21 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; 22 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
22 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; 23 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
@@ -34,6 +35,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -34,6 +35,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
34 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 35 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
35 import com.genersoft.iot.vmp.utils.DateUtil; 36 import com.genersoft.iot.vmp.utils.DateUtil;
36 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 37 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  38 +import gov.nist.javax.sip.message.SIPResponse;
37 import org.slf4j.Logger; 39 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory; 40 import org.slf4j.LoggerFactory;
39 import org.springframework.beans.factory.annotation.Autowired; 41 import org.springframework.beans.factory.annotation.Autowired;
@@ -95,7 +97,6 @@ public class PlayServiceImpl implements IPlayService { @@ -95,7 +97,6 @@ public class PlayServiceImpl implements IPlayService {
95 @Autowired 97 @Autowired
96 private VideoStreamSessionManager streamSession; 98 private VideoStreamSessionManager streamSession;
97 99
98 -  
99 @Autowired 100 @Autowired
100 private IDeviceService deviceService; 101 private IDeviceService deviceService;
101 102
@@ -108,25 +109,25 @@ public class PlayServiceImpl implements IPlayService { @@ -108,25 +109,25 @@ public class PlayServiceImpl implements IPlayService {
108 @Autowired 109 @Autowired
109 private ZlmHttpHookSubscribe subscribe; 110 private ZlmHttpHookSubscribe subscribe;
110 111
111 - @Autowired  
112 - private SSRCFactory ssrcFactory;  
113 -  
114 - @Autowired  
115 - private RedisTemplate<Object, Object> redisTemplate;  
116 -  
117 112
118 @Override 113 @Override
119 public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback) { 114 public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback) {
120 if (mediaServerItem == null) { 115 if (mediaServerItem == null) {
  116 + logger.warn("[点播] 未找到可用的zlm deviceId: {},channelId:{}", deviceId, channelId);
121 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm"); 117 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm");
122 } 118 }
123 119
124 Device device = redisCatchStorage.getDevice(deviceId); 120 Device device = redisCatchStorage.getDevice(deviceId);
  121 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE") && !mediaServerItem.isRtpEnable()) {
  122 + logger.warn("[点播] 单端口收流时不支持TCP主动方式收流 deviceId: {},channelId:{}", deviceId, channelId);
  123 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "单端口收流时不支持TCP主动方式收流");
  124 + }
125 InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); 125 InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
126 if (inviteInfo != null ) { 126 if (inviteInfo != null ) {
127 if (inviteInfo.getStreamInfo() == null) { 127 if (inviteInfo.getStreamInfo() == null) {
128 // 点播发起了但是尚未成功, 仅注册回调等待结果即可 128 // 点播发起了但是尚未成功, 仅注册回调等待结果即可
129 inviteStreamService.once(InviteSessionType.PLAY, deviceId, channelId, null, callback); 129 inviteStreamService.once(InviteSessionType.PLAY, deviceId, channelId, null, callback);
  130 + logger.info("[点播开始] 已经请求中,等待结果, deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
130 return inviteInfo.getSsrcInfo(); 131 return inviteInfo.getSsrcInfo();
131 }else { 132 }else {
132 StreamInfo streamInfo = inviteInfo.getStreamInfo(); 133 StreamInfo streamInfo = inviteInfo.getStreamInfo();
@@ -149,6 +150,7 @@ public class PlayServiceImpl implements IPlayService { @@ -149,6 +150,7 @@ public class PlayServiceImpl implements IPlayService {
149 InviteErrorCode.SUCCESS.getCode(), 150 InviteErrorCode.SUCCESS.getCode(),
150 InviteErrorCode.SUCCESS.getMsg(), 151 InviteErrorCode.SUCCESS.getMsg(),
151 streamInfo); 152 streamInfo);
  153 + logger.info("[点播已存在] 直接返回, deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
152 return inviteInfo.getSsrcInfo(); 154 return inviteInfo.getSsrcInfo();
153 }else { 155 }else {
154 // 点播发起了但是尚未成功, 仅注册回调等待结果即可 156 // 点播发起了但是尚未成功, 仅注册回调等待结果即可
@@ -171,7 +173,6 @@ public class PlayServiceImpl implements IPlayService { @@ -171,7 +173,6 @@ public class PlayServiceImpl implements IPlayService {
171 null); 173 null);
172 return null; 174 return null;
173 } 175 }
174 - // TODO 记录点播的状态  
175 play(mediaServerItem, ssrcInfo, device, channelId, callback); 176 play(mediaServerItem, ssrcInfo, device, channelId, callback);
176 return ssrcInfo; 177 return ssrcInfo;
177 } 178 }
@@ -187,8 +188,8 @@ public class PlayServiceImpl implements IPlayService { @@ -187,8 +188,8 @@ public class PlayServiceImpl implements IPlayService {
187 null); 188 null);
188 return; 189 return;
189 } 190 }
190 - logger.info("[点播开始] deviceId: {}, channelId: {},码流类型:{}, 收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}",  
191 - device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", ssrcInfo.getPort(), 191 + logger.info("[点播开始] deviceId: {}, channelId: {},码流类型:{}, 收流端口: {}, STREAM:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
  192 + device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", ssrcInfo.getPort(), ssrcInfo.getStream(),
192 device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); 193 device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
193 //端口获取失败的ssrcInfo 没有必要发送点播指令 194 //端口获取失败的ssrcInfo 没有必要发送点播指令
194 if (ssrcInfo.getPort() <= 0) { 195 if (ssrcInfo.getPort() <= 0) {
@@ -219,16 +220,6 @@ public class PlayServiceImpl implements IPlayService { @@ -219,16 +220,6 @@ public class PlayServiceImpl implements IPlayService {
219 device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", 220 device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流",
220 ssrcInfo.getPort(), ssrcInfo.getSsrc()); 221 ssrcInfo.getPort(), ssrcInfo.getSsrc());
221 222
222 - // 点播超时回复BYE 同时释放ssrc以及此次点播的资源  
223 -// InviteInfo inviteInfoForTimeout = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.play, device.getDeviceId(), channelId);  
224 -// if (inviteInfoForTimeout == null) {  
225 -// return;  
226 -// }  
227 -// if (InviteSessionStatus.ok == inviteInfoForTimeout.getStatus() ) {  
228 -// // TODO 发送bye  
229 -// }else {  
230 -// // TODO 发送cancel  
231 -// }  
232 callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null); 223 callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
233 inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, 224 inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
234 InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null); 225 InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
@@ -272,99 +263,10 @@ public class PlayServiceImpl implements IPlayService { @@ -272,99 +263,10 @@ public class PlayServiceImpl implements IPlayService {
272 logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channelId, 263 logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channelId,
273 device.isSwitchPrimarySubStream() ? "辅码流" : "主码流"); 264 device.isSwitchPrimarySubStream() ? "辅码流" : "主码流");
274 snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channelId, ssrcInfo.getStream()); 265 snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channelId, ssrcInfo.getStream());
275 - }, (event) -> {  
276 - inviteInfo.setStatus(InviteSessionStatus.ok);  
277 -  
278 - ResponseEvent responseEvent = (ResponseEvent) event.event;  
279 - String contentString = new String(responseEvent.getResponse().getRawContent());  
280 - // 获取ssrc  
281 - int ssrcIndex = contentString.indexOf("y=");  
282 - // 检查是否有y字段  
283 - if (ssrcIndex >= 0) {  
284 - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容  
285 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim();  
286 - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理  
287 - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {  
288 - if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {  
289 - tcpActiveHandler(device, channelId, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);  
290 - }  
291 - return;  
292 - }  
293 - logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);  
294 - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {  
295 - logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);  
296 - // 释放ssrc  
297 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
298 - // 单端口模式streamId也有变化,重新设置监听即可  
299 - if (!mediaServerItem.isRtpEnable()) {  
300 - // 添加订阅  
301 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
302 - subscribe.removeSubscribe(hookSubscribe);  
303 - String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();  
304 - hookSubscribe.getContent().put("stream", stream);  
305 - inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);  
306 - subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {  
307 - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);  
308 - dynamicTask.stop(timeOutTaskKey);  
309 - // hook响应  
310 - StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, hookParam, device.getDeviceId(), channelId);  
311 - if (streamInfo == null){  
312 - callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),  
313 - InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);  
314 - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,  
315 - InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),  
316 - InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);  
317 - return;  
318 - }  
319 - callback.run(InviteErrorCode.SUCCESS.getCode(),  
320 - InviteErrorCode.SUCCESS.getMsg(), streamInfo);  
321 - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,  
322 - InviteErrorCode.SUCCESS.getCode(),  
323 - InviteErrorCode.SUCCESS.getMsg(),  
324 - streamInfo);  
325 - snapOnPlay(mediaServerItemInUse, device.getDeviceId(), channelId, stream);  
326 - });  
327 - return;  
328 - }  
329 -  
330 - // 更新ssrc  
331 - Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);  
332 - if (!result) {  
333 - try {  
334 - logger.warn("[点播] 更新ssrc失败,停止点播 {}/{}", device.getDeviceId(), channelId);  
335 - cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);  
336 - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {  
337 - logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());  
338 - }  
339 -  
340 - dynamicTask.stop(timeOutTaskKey);  
341 - // 释放ssrc  
342 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
343 -  
344 - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());  
345 -  
346 - callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),  
347 - "下级自定义了ssrc,重新设置收流信息失败", null);  
348 - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,  
349 - InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),  
350 - "下级自定义了ssrc,重新设置收流信息失败", null);  
351 -  
352 - }else {  
353 - if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) {  
354 - inviteStreamService.removeInviteInfo(inviteInfo);  
355 - }  
356 - ssrcInfo.setSsrc(ssrcInResponse);  
357 - inviteInfo.setSsrcInfo(ssrcInfo);  
358 - inviteInfo.setStream(ssrcInfo.getStream());  
359 - if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {  
360 - tcpActiveHandler(device, channelId, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);  
361 - }  
362 - }  
363 - }else {  
364 - logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");  
365 - }  
366 - }  
367 - inviteStreamService.updateInviteInfo(inviteInfo); 266 + }, (eventResult) -> {
  267 + // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
  268 + InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId,
  269 + timeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAY);
368 }, (event) -> { 270 }, (event) -> {
369 dynamicTask.stop(timeOutTaskKey); 271 dynamicTask.stop(timeOutTaskKey);
370 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); 272 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
@@ -548,19 +450,23 @@ public class PlayServiceImpl implements IPlayService { @@ -548,19 +450,23 @@ public class PlayServiceImpl implements IPlayService {
548 String endTime, ErrorCallback<Object> callback) { 450 String endTime, ErrorCallback<Object> callback) {
549 Device device = storager.queryVideoDevice(deviceId); 451 Device device = storager.queryVideoDevice(deviceId);
550 if (device == null) { 452 if (device == null) {
551 - return; 453 + logger.warn("[录像回放] 未找到设备 deviceId: {},channelId:{}", deviceId, channelId);
  454 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到设备:" + deviceId);
552 } 455 }
  456 +
553 MediaServerItem newMediaServerItem = getNewMediaServerItem(device); 457 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
  458 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE") && ! newMediaServerItem.isRtpEnable()) {
  459 + logger.warn("[录像回放] 单端口收流时不支持TCP主动方式收流 deviceId: {},channelId:{}", deviceId, channelId);
  460 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "单端口收流时不支持TCP主动方式收流");
  461 + }
554 String stream = null; 462 String stream = null;
555 if (newMediaServerItem.isRtpEnable()) { 463 if (newMediaServerItem.isRtpEnable()) {
556 String startTimeStr = startTime.replace("-", "") 464 String startTimeStr = startTime.replace("-", "")
557 .replace(":", "") 465 .replace(":", "")
558 .replace(" ", ""); 466 .replace(" ", "");
559 - System.out.println(startTimeStr);  
560 String endTimeTimeStr = endTime.replace("-", "") 467 String endTimeTimeStr = endTime.replace("-", "")
561 .replace(":", "") 468 .replace(":", "")
562 .replace(" ", ""); 469 .replace(" ", "");
563 - System.out.println(endTimeTimeStr);  
564 stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr; 470 stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr;
565 } 471 }
566 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); 472 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
@@ -636,84 +542,13 @@ public class PlayServiceImpl implements IPlayService { @@ -636,84 +542,13 @@ public class PlayServiceImpl implements IPlayService {
636 try { 542 try {
637 cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, 543 cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime,
638 hookEvent, eventResult -> { 544 hookEvent, eventResult -> {
639 - inviteInfo.setStatus(InviteSessionStatus.ok);  
640 - ResponseEvent responseEvent = (ResponseEvent) eventResult.event;  
641 - String contentString = new String(responseEvent.getResponse().getRawContent());  
642 - // 获取ssrc  
643 - int ssrcIndex = contentString.indexOf("y=");  
644 - // 检查是否有y字段  
645 - if (ssrcIndex >= 0) {  
646 - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容  
647 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
648 - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理  
649 - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {  
650 - if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {  
651 - tcpActiveHandler(device, channelId, contentString, mediaServerItem, playBackTimeOutTaskKey, ssrcInfo, callback);  
652 - }  
653 - return;  
654 - }  
655 - logger.info("[录像回放] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);  
656 - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {  
657 - logger.info("[录像回放] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);  
658 -  
659 - // 释放ssrc  
660 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
661 -  
662 - // 单端口模式streamId也有变化,需要重新设置监听  
663 - if (!mediaServerItem.isRtpEnable()) {  
664 - // 添加订阅  
665 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
666 - subscribe.removeSubscribe(hookSubscribe);  
667 - String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();  
668 - hookSubscribe.getContent().put("stream", stream);  
669 - inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);  
670 - subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {  
671 - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);  
672 - dynamicTask.stop(playBackTimeOutTaskKey);  
673 - // hook响应  
674 - hookEvent.response(mediaServerItemInUse, hookParam);  
675 - });  
676 - }  
677 - // 更新ssrc  
678 - Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);  
679 - if (!result) {  
680 - try {  
681 - logger.warn("[录像回放] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);  
682 - cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);  
683 - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {  
684 - logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());  
685 -  
686 - }  
687 -  
688 - dynamicTask.stop(playBackTimeOutTaskKey);  
689 - // 释放ssrc  
690 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
691 -  
692 - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());  
693 -  
694 - callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),  
695 - "下级自定义了ssrc,重新设置收流信息失败", null);  
696 -  
697 - }else {  
698 - if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) {  
699 - inviteStreamService.removeInviteInfo(inviteInfo);  
700 - }  
701 -  
702 - ssrcInfo.setSsrc(ssrcInResponse);  
703 - inviteInfo.setSsrcInfo(ssrcInfo);  
704 - inviteInfo.setStream(ssrcInfo.getStream());  
705 - if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {  
706 - tcpActiveHandler(device, channelId, contentString, mediaServerItem, playBackTimeOutTaskKey, ssrcInfo, callback);  
707 - }  
708 - }  
709 - }else {  
710 - logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");  
711 - }  
712 - }  
713 - inviteStreamService.updateInviteInfo(inviteInfo); 545 + // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
  546 + InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId,
  547 + playBackTimeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAYBACK);
  548 +
714 }, errorEvent); 549 }, errorEvent);
715 } catch (InvalidArgumentException | SipException | ParseException e) { 550 } catch (InvalidArgumentException | SipException | ParseException e) {
716 - logger.error("[命令发送失败] 回放: {}", e.getMessage()); 551 + logger.error("[命令发送失败] 录像回放: {}", e.getMessage());
717 552
718 SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(); 553 SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();
719 eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent; 554 eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent;
@@ -724,6 +559,121 @@ public class PlayServiceImpl implements IPlayService { @@ -724,6 +559,121 @@ public class PlayServiceImpl implements IPlayService {
724 } 559 }
725 560
726 561
  562 + private void InviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, MediaServerItem mediaServerItem,
  563 + Device device, String channelId, String timeOutTaskKey, ErrorCallback<Object> callback,
  564 + InviteInfo inviteInfo, InviteSessionType inviteSessionType){
  565 + inviteInfo.setStatus(InviteSessionStatus.ok);
  566 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
  567 + String contentString = new String(responseEvent.getResponse().getRawContent());
  568 + String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString);
  569 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  570 + // ssrc 一致
  571 + if (mediaServerItem.isRtpEnable()) {
  572 + // 多端口
  573 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  574 + tcpActiveHandler(device, channelId, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);
  575 + }
  576 + }else {
  577 + // 单端口
  578 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  579 + logger.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
  580 + }
  581 +
  582 + }
  583 + }else {
  584 + logger.info("[Invite 200OK] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  585 + // ssrc 不一致
  586 + if (mediaServerItem.isRtpEnable()) {
  587 + // 多端口
  588 + if (device.isSsrcCheck()) {
  589 + // ssrc检验
  590 + // 更新ssrc
  591 + logger.info("[Invite 200OK] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  592 + // 释放ssrc
  593 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  594 + Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
  595 + if (!result) {
  596 + try {
  597 + logger.warn("[Invite 200OK] 更新ssrc失败,停止点播 {}/{}", device.getDeviceId(), channelId);
  598 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  599 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  600 + logger.error("[命令发送失败] 停止播放, 发送BYE: {}", e.getMessage());
  601 + }
  602 +
  603 + dynamicTask.stop(timeOutTaskKey);
  604 + // 释放ssrc
  605 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  606 +
  607 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  608 +
  609 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  610 + "下级自定义了ssrc,重新设置收流信息失败", null);
  611 + inviteStreamService.call(inviteSessionType, device.getDeviceId(), channelId, null,
  612 + InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  613 + "下级自定义了ssrc,重新设置收流信息失败", null);
  614 +
  615 + }else {
  616 + ssrcInfo.setSsrc(ssrcInResponse);
  617 + inviteInfo.setSsrcInfo(ssrcInfo);
  618 + inviteInfo.setStream(ssrcInfo.getStream());
  619 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  620 + if (mediaServerItem.isRtpEnable()) {
  621 + tcpActiveHandler(device, channelId, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);
  622 + }else {
  623 + logger.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
  624 + }
  625 + }
  626 + inviteStreamService.updateInviteInfo(inviteInfo);
  627 + }
  628 + }
  629 + }else {
  630 + if (ssrcInResponse != null) {
  631 + // 单端口
  632 + // 重新订阅流上线
  633 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp",
  634 + ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  635 + subscribe.removeSubscribe(hookSubscribe);
  636 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(inviteInfo.getDeviceId(),
  637 + inviteInfo.getChannelId(), null, inviteInfo.getStream());
  638 + streamSession.remove(inviteInfo.getDeviceId(),
  639 + inviteInfo.getChannelId(), inviteInfo.getStream());
  640 +
  641 + String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
  642 + hookSubscribe.getContent().put("stream", stream);
  643 +
  644 + inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);
  645 + streamSession.put(device.getDeviceId(), channelId, ssrcTransaction.getCallId(),
  646 + stream, ssrcInResponse, mediaServerItem.getId(), (SIPResponse) responseEvent.getResponse(), inviteSessionType);
  647 + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
  648 + logger.info("[Invite 200OK] ssrc修正后收到订阅消息: " + hookParam);
  649 + dynamicTask.stop(timeOutTaskKey);
  650 + subscribe.removeSubscribe(hookSubscribe);
  651 + // hook响应
  652 + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, hookParam, device.getDeviceId(), channelId);
  653 + if (streamInfo == null){
  654 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  655 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  656 + inviteStreamService.call(inviteSessionType, device.getDeviceId(), channelId, null,
  657 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  658 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  659 + return;
  660 + }
  661 + callback.run(InviteErrorCode.SUCCESS.getCode(),
  662 + InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  663 + inviteStreamService.call(inviteSessionType, device.getDeviceId(), channelId, null,
  664 + InviteErrorCode.SUCCESS.getCode(),
  665 + InviteErrorCode.SUCCESS.getMsg(),
  666 + streamInfo);
  667 + if (inviteSessionType == InviteSessionType.PLAY) {
  668 + snapOnPlay(mediaServerItemInUse, device.getDeviceId(), channelId, stream);
  669 + }
  670 + });
  671 + }
  672 + }
  673 + }
  674 + }
  675 +
  676 +
727 677
728 @Override 678 @Override
729 public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) { 679 public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) {
@@ -738,7 +688,17 @@ public class PlayServiceImpl implements IPlayService { @@ -738,7 +688,17 @@ public class PlayServiceImpl implements IPlayService {
738 null); 688 null);
739 return; 689 return;
740 } 690 }
741 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); 691 + String stream = null;
  692 + if (newMediaServerItem.isRtpEnable()) {
  693 + String startTimeStr = startTime.replace("-", "")
  694 + .replace(":", "")
  695 + .replace(" ", "");
  696 + String endTimeTimeStr = endTime.replace("-", "")
  697 + .replace(":", "")
  698 + .replace(" ", "");
  699 + stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr;
  700 + }
  701 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
742 download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, callback); 702 download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, callback);
743 } 703 }
744 704
@@ -806,79 +766,9 @@ public class PlayServiceImpl implements IPlayService { @@ -806,79 +766,9 @@ public class PlayServiceImpl implements IPlayService {
806 try { 766 try {
807 cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, 767 cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed,
808 hookEvent, errorEvent, eventResult ->{ 768 hookEvent, errorEvent, eventResult ->{
809 - inviteInfo.setStatus(InviteSessionStatus.ok);  
810 - ResponseEvent responseEvent = (ResponseEvent) eventResult.event;  
811 - String contentString = new String(responseEvent.getResponse().getRawContent());  
812 - // 获取ssrc  
813 - int ssrcIndex = contentString.indexOf("y=");  
814 - // 检查是否有y字段  
815 - if (ssrcIndex >= 0) {  
816 - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容  
817 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
818 - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理  
819 - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {  
820 - if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {  
821 - tcpActiveHandler(device, channelId, contentString, mediaServerItem, downLoadTimeOutTaskKey, ssrcInfo, callback);  
822 - }  
823 - return;  
824 - }  
825 - logger.info("[录像下载] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);  
826 - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {  
827 - logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);  
828 -  
829 - // 释放ssrc  
830 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
831 -  
832 - // 单端口模式streamId也有变化,需要重新设置监听  
833 - if (!mediaServerItem.isRtpEnable()) {  
834 - // 添加订阅  
835 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
836 - subscribe.removeSubscribe(hookSubscribe);  
837 - String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();  
838 - hookSubscribe.getContent().put("stream", stream);  
839 - inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);  
840 - subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {  
841 - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);  
842 - dynamicTask.stop(downLoadTimeOutTaskKey);  
843 - hookEvent.response(mediaServerItemInUse, hookParam);  
844 - });  
845 - }  
846 -  
847 - // 更新ssrc  
848 - Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);  
849 - if (!result) {  
850 - try {  
851 - logger.warn("[录像下载] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);  
852 - cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);  
853 - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {  
854 - logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());  
855 - }  
856 -  
857 - dynamicTask.stop(downLoadTimeOutTaskKey);  
858 - // 释放ssrc  
859 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
860 -  
861 - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());  
862 -  
863 - callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),  
864 - "下级自定义了ssrc,重新设置收流信息失败", null);  
865 -  
866 - }else {  
867 - if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) {  
868 - inviteStreamService.removeInviteInfo(inviteInfo);  
869 - }  
870 - ssrcInfo.setSsrc(ssrcInResponse);  
871 - inviteInfo.setSsrcInfo(ssrcInfo);  
872 - inviteInfo.setStream(ssrcInfo.getStream());  
873 - if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {  
874 - tcpActiveHandler(device, channelId, contentString, mediaServerItem, downLoadTimeOutTaskKey, ssrcInfo, callback);  
875 - }  
876 - }  
877 - }else {  
878 - logger.info("[录像下载] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");  
879 - }  
880 - }  
881 - inviteStreamService.updateInviteInfo(inviteInfo); 769 + // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
  770 + InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId,
  771 + downLoadTimeOutTaskKey, callback, inviteInfo, InviteSessionType.DOWNLOAD);
882 }); 772 });
883 } catch (InvalidArgumentException | SipException | ParseException e) { 773 } catch (InvalidArgumentException | SipException | ParseException e) {
884 logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); 774 logger.error("[命令发送失败] 录像下载: {}", e.getMessage());
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
@@ -7,6 +7,7 @@ import java.time.LocalDateTime; @@ -7,6 +7,7 @@ import java.time.LocalDateTime;
7 import java.time.ZoneId; 7 import java.time.ZoneId;
8 import java.time.format.DateTimeFormatter; 8 import java.time.format.DateTimeFormatter;
9 import java.time.format.DateTimeParseException; 9 import java.time.format.DateTimeParseException;
  10 +import java.time.temporal.ChronoUnit;
10 import java.time.temporal.TemporalAccessor; 11 import java.time.temporal.TemporalAccessor;
11 12
12 import java.util.Locale; 13 import java.util.Locale;
@@ -106,4 +107,9 @@ public class DateUtil { @@ -106,4 +107,9 @@ public class DateUtil {
106 LocalDateTime nowDateTime = LocalDateTime.now(); 107 LocalDateTime nowDateTime = LocalDateTime.now();
107 return formatterISO8601.format(nowDateTime); 108 return formatterISO8601.format(nowDateTime);
108 } 109 }
  110 +
  111 + public static long getDifferenceForNow(String keepaliveTime) {
  112 + Instant beforeInstant = Instant.from(formatter.parse(keepaliveTime));
  113 + return ChronoUnit.MILLIS.between(beforeInstant, Instant.now());
  114 + }
109 } 115 }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -111,7 +111,7 @@ public class PlayController { @@ -111,7 +111,7 @@ public class PlayController {
111 wvpResult.setCode(ErrorCode.ERROR100.getCode()); 111 wvpResult.setCode(ErrorCode.ERROR100.getCode());
112 wvpResult.setMsg("点播超时"); 112 wvpResult.setMsg("点播超时");
113 requestMessage.setData(wvpResult); 113 requestMessage.setData(wvpResult);
114 - resultHolder.invokeResult(requestMessage); 114 + resultHolder.invokeAllResult(requestMessage);
115 inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); 115 inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
116 storager.stopPlay(deviceId, channelId); 116 storager.stopPlay(deviceId, channelId);
117 }); 117 });
@@ -166,7 +166,7 @@ public class PlayController { @@ -166,7 +166,7 @@ public class PlayController {
166 } 166 }
167 if (InviteSessionStatus.ok == inviteInfo.getStatus()) { 167 if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
168 try { 168 try {
169 - logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId); 169 + logger.info("[停止点播] {}/{}", device.getDeviceId(), channelId);
170 cmder.streamByeCmd(device, channelId, inviteInfo.getStream(), null, null); 170 cmder.streamByeCmd(device, channelId, inviteInfo.getStream(), null, null);
171 } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { 171 } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
172 logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage()); 172 logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());