Commit ccecda78599323872a3e4cd664c7892856c32397

Authored by 648540858
Committed by GitHub
2 parents 7e48d847 21258d6b

Merge pull request #845 from 648540858/wvp-28181-2.0-test

Wvp 28181 2.0 test
Showing 37 changed files with 1454 additions and 1202 deletions
src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  4 +
  5 +/**
  6 + * 记录每次发送invite消息的状态
  7 + */
  8 +public class InviteInfo {
  9 +
  10 + private String deviceId;
  11 +
  12 + private String channelId;
  13 +
  14 + private String stream;
  15 +
  16 + private SSRCInfo ssrcInfo;
  17 +
  18 + private String receiveIp;
  19 +
  20 + private Integer receivePort;
  21 +
  22 + private String streamMode;
  23 +
  24 + private InviteSessionType type;
  25 +
  26 + private InviteSessionStatus status;
  27 +
  28 + private StreamInfo streamInfo;
  29 +
  30 +
  31 + public static InviteInfo getinviteInfo(String deviceId, String channelId, String stream, SSRCInfo ssrcInfo,
  32 + String receiveIp, Integer receivePort, String streamMode,
  33 + InviteSessionType type, InviteSessionStatus status) {
  34 + InviteInfo inviteInfo = new InviteInfo();
  35 + inviteInfo.setDeviceId(deviceId);
  36 + inviteInfo.setChannelId(channelId);
  37 + inviteInfo.setStream(stream);
  38 + inviteInfo.setSsrcInfo(ssrcInfo);
  39 + inviteInfo.setReceiveIp(receiveIp);
  40 + inviteInfo.setReceivePort(receivePort);
  41 + inviteInfo.setStreamMode(streamMode);
  42 + inviteInfo.setType(type);
  43 + inviteInfo.setStatus(status);
  44 + return inviteInfo;
  45 + }
  46 +
  47 + public String getDeviceId() {
  48 + return deviceId;
  49 + }
  50 +
  51 + public void setDeviceId(String deviceId) {
  52 + this.deviceId = deviceId;
  53 + }
  54 +
  55 + public String getChannelId() {
  56 + return channelId;
  57 + }
  58 +
  59 + public void setChannelId(String channelId) {
  60 + this.channelId = channelId;
  61 + }
  62 +
  63 + public InviteSessionType getType() {
  64 + return type;
  65 + }
  66 +
  67 + public void setType(InviteSessionType type) {
  68 + this.type = type;
  69 + }
  70 +
  71 + public InviteSessionStatus getStatus() {
  72 + return status;
  73 + }
  74 +
  75 + public void setStatus(InviteSessionStatus status) {
  76 + this.status = status;
  77 + }
  78 +
  79 + public StreamInfo getStreamInfo() {
  80 + return streamInfo;
  81 + }
  82 +
  83 + public void setStreamInfo(StreamInfo streamInfo) {
  84 + this.streamInfo = streamInfo;
  85 + }
  86 +
  87 + public String getStream() {
  88 + return stream;
  89 + }
  90 +
  91 + public void setStream(String stream) {
  92 + this.stream = stream;
  93 + }
  94 +
  95 + public SSRCInfo getSsrcInfo() {
  96 + return ssrcInfo;
  97 + }
  98 +
  99 + public void setSsrcInfo(SSRCInfo ssrcInfo) {
  100 + this.ssrcInfo = ssrcInfo;
  101 + }
  102 +
  103 + public String getReceiveIp() {
  104 + return receiveIp;
  105 + }
  106 +
  107 + public void setReceiveIp(String receiveIp) {
  108 + this.receiveIp = receiveIp;
  109 + }
  110 +
  111 + public Integer getReceivePort() {
  112 + return receivePort;
  113 + }
  114 +
  115 + public void setReceivePort(Integer receivePort) {
  116 + this.receivePort = receivePort;
  117 + }
  118 +
  119 + public String getStreamMode() {
  120 + return streamMode;
  121 + }
  122 +
  123 + public void setStreamMode(String streamMode) {
  124 + this.streamMode = streamMode;
  125 + }
  126 +}
src/main/java/com/genersoft/iot/vmp/common/InviteSessionStatus.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +/**
  4 + * 标识invite消息发出后的各个状态,
  5 + * 收到ok钱停止invite发送cancel,
  6 + * 收到200ok后发送BYE停止invite
  7 + */
  8 +public enum InviteSessionStatus {
  9 + ready,
  10 + ok,
  11 +}
src/main/java/com/genersoft/iot/vmp/common/InviteSessionType.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +public enum InviteSessionType {
  4 + PLAY,
  5 + PLAYBACK,
  6 + DOWNLOAD
  7 +}
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -16,8 +16,6 @@ public class VideoManagerConstants { @@ -16,8 +16,6 @@ public class VideoManagerConstants {
16 16
17 public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_"; 17 public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_";
18 18
19 - public static final String MEDIA_STREAM_PREFIX = "VMP_MEDIA_STREAM";  
20 -  
21 public static final String DEVICE_PREFIX = "VMP_DEVICE_"; 19 public static final String DEVICE_PREFIX = "VMP_DEVICE_";
22 20
23 // 设备同步完成 21 // 设备同步完成
@@ -28,9 +26,10 @@ public class VideoManagerConstants { @@ -28,9 +26,10 @@ public class VideoManagerConstants {
28 public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_"; 26 public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_";
29 27
30 // TODO 此处多了一个_,暂不修改 28 // TODO 此处多了一个_,暂不修改
31 - public static final String PLAYER_PREFIX = "VMP_PLAYER_";  
32 - public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_";  
33 - public static final String DOWNLOAD_PREFIX = "VMP_DOWNLOAD_"; 29 + public static final String INVITE_PREFIX = "VMP_INVITE";
  30 + public static final String PLAYER_PREFIX = "VMP_INVITE_PLAY_";
  31 + public static final String PLAY_BLACK_PREFIX = "VMP_INVITE_PLAYBACK_";
  32 + public static final String DOWNLOAD_PREFIX = "VMP_INVITE_DOWNLOAD_";
34 33
35 public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_"; 34 public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_";
36 35
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
@@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.conf; @@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.conf;
2 2
3 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 3 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
4 import com.genersoft.iot.vmp.service.IMediaServerService; 4 import com.genersoft.iot.vmp.service.IMediaServerService;
5 -import org.apache.catalina.connector.ClientAbortException;  
6 import org.apache.http.HttpHost; 5 import org.apache.http.HttpHost;
7 import org.apache.http.HttpRequest; 6 import org.apache.http.HttpRequest;
8 import org.apache.http.HttpResponse; 7 import org.apache.http.HttpResponse;
@@ -194,11 +193,11 @@ public class ProxyServletConfig { @@ -194,11 +193,11 @@ public class ProxyServletConfig {
194 } catch (IOException ioException) { 193 } catch (IOException ioException) {
195 if (ioException instanceof ConnectException) { 194 if (ioException instanceof ConnectException) {
196 logger.error("录像服务 连接失败"); 195 logger.error("录像服务 连接失败");
197 - }else if (ioException instanceof ClientAbortException) {  
198 - /**  
199 - * TODO 使用这个代理库实现代理在遇到代理视频文件时,如果是206结果,会遇到报错蛋市目前功能正常,  
200 - * TODO 暂时去除异常处理。后续使用其他代理框架修改测试  
201 - */ 196 +// }else if (ioException instanceof ClientAbortException) {
  197 +// /**
  198 +// * TODO 使用这个代理库实现代理在遇到代理视频文件时,如果是206结果,会遇到报错蛋市目前功能正常,
  199 +// * TODO 暂时去除异常处理。后续使用其他代理框架修改测试
  200 +// */
202 201
203 }else { 202 }else {
204 logger.error("录像服务 代理失败: ", e); 203 logger.error("录像服务 代理失败: ", e);
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java
@@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean; @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 public enum InviteStreamType { 3 public enum InviteStreamType {
4 4
5 - PLAY,PLAYBACK,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY 5 + PLAY,PLAYBACK,DOWNLOAD,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY
6 6
7 7
8 } 8 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java
1 package com.genersoft.iot.vmp.gb28181.bean; 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 3 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 4
5 public class SsrcTransaction { 5 public class SsrcTransaction {
6 6
@@ -13,7 +13,7 @@ public class SsrcTransaction { @@ -13,7 +13,7 @@ public class SsrcTransaction {
13 13
14 private SipTransactionInfo sipTransactionInfo; 14 private SipTransactionInfo sipTransactionInfo;
15 15
16 - private VideoStreamSessionManager.SessionType type; 16 + private InviteSessionType type;
17 17
18 public String getDeviceId() { 18 public String getDeviceId() {
19 return deviceId; 19 return deviceId;
@@ -63,11 +63,11 @@ public class SsrcTransaction { @@ -63,11 +63,11 @@ public class SsrcTransaction {
63 this.ssrc = ssrc; 63 this.ssrc = ssrc;
64 } 64 }
65 65
66 - public VideoStreamSessionManager.SessionType getType() { 66 + public InviteSessionType getType() {
67 return type; 67 return type;
68 } 68 }
69 69
70 - public void setType(VideoStreamSessionManager.SessionType type) { 70 + public void setType(InviteSessionType type) {
71 this.type = type; 71 this.type = type;
72 } 72 }
73 73
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
1 package com.genersoft.iot.vmp.gb28181.session; 1 package com.genersoft.iot.vmp.gb28181.session;
2 2
  3 +import com.genersoft.iot.vmp.common.InviteSessionType;
3 import com.genersoft.iot.vmp.common.VideoManagerConstants; 4 import com.genersoft.iot.vmp.common.VideoManagerConstants;
4 import com.genersoft.iot.vmp.conf.UserSetting; 5 import com.genersoft.iot.vmp.conf.UserSetting;
5 import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; 6 import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
@@ -27,12 +28,6 @@ public class VideoStreamSessionManager { @@ -27,12 +28,6 @@ public class VideoStreamSessionManager {
27 @Autowired 28 @Autowired
28 private RedisTemplate<Object, Object> redisTemplate; 29 private RedisTemplate<Object, Object> redisTemplate;
29 30
30 - public enum SessionType {  
31 - play,  
32 - playback,  
33 - download  
34 - }  
35 -  
36 /** 31 /**
37 * 添加一个点播/回放的事务信息 32 * 添加一个点播/回放的事务信息
38 * 后续可以通过流Id/callID 33 * 后续可以通过流Id/callID
@@ -43,7 +38,7 @@ public class VideoStreamSessionManager { @@ -43,7 +38,7 @@ public class VideoStreamSessionManager {
43 * @param mediaServerId 所使用的流媒体ID 38 * @param mediaServerId 所使用的流媒体ID
44 * @param response 回复 39 * @param response 回复
45 */ 40 */
46 - public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, SessionType type){ 41 + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type){
47 SsrcTransaction ssrcTransaction = new SsrcTransaction(); 42 SsrcTransaction ssrcTransaction = new SsrcTransaction();
48 ssrcTransaction.setDeviceId(deviceId); 43 ssrcTransaction.setDeviceId(deviceId);
49 ssrcTransaction.setChannelId(channelId); 44 ssrcTransaction.setChannelId(channelId);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -4,7 +4,6 @@ import com.genersoft.iot.vmp.common.StreamInfo; @@ -4,7 +4,6 @@ import com.genersoft.iot.vmp.common.StreamInfo;
4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 import com.genersoft.iot.vmp.gb28181.bean.Device; 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; 6 import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
7 -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;  
8 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 7 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
9 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 8 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
10 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 9 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -109,7 +108,7 @@ public interface ISIPCommander { @@ -109,7 +108,7 @@ public interface ISIPCommander {
109 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss 108 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
110 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss 109 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
111 */ 110 */
112 - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; 111 + void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
113 112
114 /** 113 /**
115 * 请求历史媒体下载 114 * 请求历史媒体下载
@@ -121,7 +120,7 @@ public interface ISIPCommander { @@ -121,7 +120,7 @@ public interface ISIPCommander {
121 * @param downloadSpeed 下载倍速参数 120 * @param downloadSpeed 下载倍速参数
122 */ 121 */
123 void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 122 void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
124 - String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, 123 + String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,
125 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; 124 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
126 125
127 /** 126 /**
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
1 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.common.StreamInfo; 5 import com.genersoft.iot.vmp.common.StreamInfo;
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;
@@ -350,7 +351,7 @@ public class SIPCommander implements ISIPCommander { @@ -350,7 +351,7 @@ public class SIPCommander implements ISIPCommander {
350 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 351 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
351 ResponseEvent responseEvent = (ResponseEvent) e.event; 352 ResponseEvent responseEvent = (ResponseEvent) e.event;
352 SIPResponse response = (SIPResponse) responseEvent.getResponse(); 353 SIPResponse response = (SIPResponse) responseEvent.getResponse();
353 - streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play); 354 + streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAY);
354 okEvent.response(e); 355 okEvent.response(e);
355 }); 356 });
356 } 357 }
@@ -365,11 +366,11 @@ public class SIPCommander implements ISIPCommander { @@ -365,11 +366,11 @@ public class SIPCommander implements ISIPCommander {
365 */ 366 */
366 @Override 367 @Override
367 public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 368 public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
368 - String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, 369 + String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent,
369 SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { 370 SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
370 371
371 372
372 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getSdpIp(), mediaServerItem.getIp(), ssrcInfo.getPort()); 373 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
373 String sdpIp; 374 String sdpIp;
374 if (!ObjectUtils.isEmpty(device.getSdpIp())) { 375 if (!ObjectUtils.isEmpty(device.getSdpIp())) {
375 sdpIp = device.getSdpIp(); 376 sdpIp = device.getSdpIp();
@@ -442,8 +443,7 @@ public class SIPCommander implements ISIPCommander { @@ -442,8 +443,7 @@ public class SIPCommander implements ISIPCommander {
442 // 添加订阅 443 // 添加订阅
443 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { 444 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
444 if (hookEvent != null) { 445 if (hookEvent != null) {
445 - InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), "rtp", ssrcInfo.getStream());  
446 - hookEvent.call(inviteStreamInfo); 446 + hookEvent.response(mediaServerItemInUse, json);
447 } 447 }
448 subscribe.removeSubscribe(hookSubscribe); 448 subscribe.removeSubscribe(hookSubscribe);
449 }); 449 });
@@ -452,12 +452,9 @@ public class SIPCommander implements ISIPCommander { @@ -452,12 +452,9 @@ public class SIPCommander implements ISIPCommander {
452 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { 452 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
453 ResponseEvent responseEvent = (ResponseEvent) event.event; 453 ResponseEvent responseEvent = (ResponseEvent) event.event;
454 SIPResponse response = (SIPResponse) responseEvent.getResponse(); 454 SIPResponse response = (SIPResponse) responseEvent.getResponse();
455 - streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.playback); 455 + streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK);
456 okEvent.response(event); 456 okEvent.response(event);
457 }); 457 });
458 - if (inviteStreamCallback != null) {  
459 - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), "rtp", ssrcInfo.getStream()));  
460 - }  
461 } 458 }
462 459
463 /** 460 /**
@@ -472,10 +469,10 @@ public class SIPCommander implements ISIPCommander { @@ -472,10 +469,10 @@ public class SIPCommander implements ISIPCommander {
472 @Override 469 @Override
473 public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 470 public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
474 String startTime, String endTime, int downloadSpeed, 471 String startTime, String endTime, int downloadSpeed,
475 - InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, 472 + ZlmHttpHookSubscribe.Event hookEvent,
476 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { 473 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
477 474
478 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getSdpIp(), mediaServerItem.getIp(), ssrcInfo.getPort()); 475 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
479 String sdpIp; 476 String sdpIp;
480 if (!ObjectUtils.isEmpty(device.getSdpIp())) { 477 if (!ObjectUtils.isEmpty(device.getSdpIp())) {
481 sdpIp = device.getSdpIp(); 478 sdpIp = device.getSdpIp();
@@ -543,13 +540,13 @@ public class SIPCommander implements ISIPCommander { @@ -543,13 +540,13 @@ public class SIPCommander implements ISIPCommander {
543 540
544 content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc 541 content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
545 logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc()); 542 logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());
546 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); 543 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
547 // 添加订阅 544 // 添加订阅
548 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); 545 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
549 String callId= newCallIdHeader.getCallId(); 546 String callId= newCallIdHeader.getCallId();
550 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { 547 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
551 logger.debug("sipc 添加订阅===callId {}",callId); 548 logger.debug("sipc 添加订阅===callId {}",callId);
552 - hookEvent.call(new InviteStreamInfo(mediaServerItem, json,callId, "rtp", ssrcInfo.getStream())); 549 + hookEvent.response(mediaServerItemInUse, json);
553 subscribe.removeSubscribe(hookSubscribe); 550 subscribe.removeSubscribe(hookSubscribe);
554 hookSubscribe.getContent().put("regist", false); 551 hookSubscribe.getContent().put("regist", false);
555 hookSubscribe.getContent().put("schema", "rtsp"); 552 hookSubscribe.getContent().put("schema", "rtsp");
@@ -567,9 +564,6 @@ public class SIPCommander implements ISIPCommander { @@ -567,9 +564,6 @@ public class SIPCommander implements ISIPCommander {
567 }); 564 });
568 565
569 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc()); 566 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
570 - if (inviteStreamCallback != null) {  
571 - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null,callId, "rtp", ssrcInfo.getStream()));  
572 - }  
573 567
574 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { 568 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
575 ResponseEvent responseEvent = (ResponseEvent) event.event; 569 ResponseEvent responseEvent = (ResponseEvent) event.event;
@@ -580,7 +574,7 @@ public class SIPCommander implements ISIPCommander { @@ -580,7 +574,7 @@ public class SIPCommander implements ISIPCommander {
580 if (ssrcIndex >= 0) { 574 if (ssrcIndex >= 0) {
581 ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); 575 ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
582 } 576 }
583 - streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download); 577 + streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);
584 okEvent.response(event); 578 okEvent.response(event);
585 }); 579 });
586 } 580 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.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.genersoft.iot.vmp.common.StreamInfo; 3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 5 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 import com.genersoft.iot.vmp.gb28181.bean.Device; 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType; 7 import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType;
@@ -15,6 +16,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP @@ -15,6 +16,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP
15 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 16 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
16 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 17 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
17 import com.genersoft.iot.vmp.service.IDeviceService; 18 import com.genersoft.iot.vmp.service.IDeviceService;
  19 +import com.genersoft.iot.vmp.service.IInviteStreamService;
18 import com.genersoft.iot.vmp.service.IMediaServerService; 20 import com.genersoft.iot.vmp.service.IMediaServerService;
19 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 21 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 22 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -26,7 +28,9 @@ import org.springframework.beans.factory.InitializingBean; @@ -26,7 +28,9 @@ import org.springframework.beans.factory.InitializingBean;
26 import org.springframework.beans.factory.annotation.Autowired; 28 import org.springframework.beans.factory.annotation.Autowired;
27 import org.springframework.stereotype.Component; 29 import org.springframework.stereotype.Component;
28 30
29 -import javax.sip.*; 31 +import javax.sip.InvalidArgumentException;
  32 +import javax.sip.RequestEvent;
  33 +import javax.sip.SipException;
30 import javax.sip.address.SipURI; 34 import javax.sip.address.SipURI;
31 import javax.sip.header.CallIdHeader; 35 import javax.sip.header.CallIdHeader;
32 import javax.sip.header.FromHeader; 36 import javax.sip.header.FromHeader;
@@ -53,6 +57,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -53,6 +57,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
53 private IRedisCatchStorage redisCatchStorage; 57 private IRedisCatchStorage redisCatchStorage;
54 58
55 @Autowired 59 @Autowired
  60 + private IInviteStreamService inviteStreamService;
  61 +
  62 + @Autowired
56 private IDeviceService deviceService; 63 private IDeviceService deviceService;
57 64
58 @Autowired 65 @Autowired
@@ -136,11 +143,6 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -136,11 +143,6 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
136 Device device = storager.queryVideoDeviceByChannelId(platformGbId); 143 Device device = storager.queryVideoDeviceByChannelId(platformGbId);
137 if (device != null) { 144 if (device != null) {
138 storager.stopPlay(device.getDeviceId(), channelId); 145 storager.stopPlay(device.getDeviceId(), channelId);
139 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);  
140 - if (streamInfo != null) {  
141 - redisCatchStorage.stopPlay(streamInfo);  
142 - mediaServerService.closeRTPServer(streamInfo.getMediaServerId(), streamInfo.getStream());  
143 - }  
144 SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null); 146 SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);
145 if (ssrcTransactionForPlay != null){ 147 if (ssrcTransactionForPlay != null){
146 if (ssrcTransactionForPlay.getCallId().equals(callIdHeader.getCallId())){ 148 if (ssrcTransactionForPlay.getCallId().equals(callIdHeader.getCallId())){
@@ -151,6 +153,14 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -151,6 +153,14 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
151 } 153 }
152 streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream()); 154 streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream());
153 } 155 }
  156 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
  157 +
  158 + if (inviteInfo != null) {
  159 + inviteStreamService.removeInviteInfo(inviteInfo);
  160 + if (inviteInfo.getStreamInfo() != null) {
  161 + mediaServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServerId(), inviteInfo.getStream());
  162 + }
  163 + }
154 } 164 }
155 SsrcTransaction ssrcTransactionForPlayBack = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callIdHeader.getCallId(), null); 165 SsrcTransaction ssrcTransactionForPlayBack = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callIdHeader.getCallId(), null);
156 if (ssrcTransactionForPlayBack != null) { 166 if (ssrcTransactionForPlayBack != null) {
@@ -160,6 +170,14 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -160,6 +170,14 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
160 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlayBack.getSsrc()); 170 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlayBack.getSsrc());
161 } 171 }
162 streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlayBack.getStream()); 172 streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlayBack.getStream());
  173 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, device.getDeviceId(), channelId);
  174 +
  175 + if (inviteInfo != null) {
  176 + inviteStreamService.removeInviteInfo(inviteInfo);
  177 + if (inviteInfo.getStreamInfo() != null) {
  178 + mediaServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServerId(), inviteInfo.getStream());
  179 + }
  180 + }
163 } 181 }
164 } 182 }
165 183
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.genersoft.iot.vmp.common.StreamInfo;
4 import com.genersoft.iot.vmp.conf.DynamicTask; 4 import com.genersoft.iot.vmp.conf.DynamicTask;
5 import com.genersoft.iot.vmp.conf.UserSetting; 5 import com.genersoft.iot.vmp.conf.UserSetting;
6 import com.genersoft.iot.vmp.gb28181.bean.*; 6 import com.genersoft.iot.vmp.gb28181.bean.*;
7 -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;  
8 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; 7 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
9 -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;  
10 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 8 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
11 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; 9 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
12 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
@@ -21,6 +19,8 @@ import com.genersoft.iot.vmp.service.IMediaServerService; @@ -21,6 +19,8 @@ import com.genersoft.iot.vmp.service.IMediaServerService;
21 import com.genersoft.iot.vmp.service.IPlayService; 19 import com.genersoft.iot.vmp.service.IPlayService;
22 import com.genersoft.iot.vmp.service.IStreamProxyService; 20 import com.genersoft.iot.vmp.service.IStreamProxyService;
23 import com.genersoft.iot.vmp.service.IStreamPushService; 21 import com.genersoft.iot.vmp.service.IStreamPushService;
  22 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  23 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
24 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 24 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
25 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 25 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
26 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; 26 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
@@ -102,9 +102,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -102,9 +102,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
102 private SIPProcessorObserver sipProcessorObserver; 102 private SIPProcessorObserver sipProcessorObserver;
103 103
104 @Autowired 104 @Autowired
105 - private VideoStreamSessionManager sessionManager;  
106 -  
107 - @Autowired  
108 private UserSetting userSetting; 105 private UserSetting userSetting;
109 106
110 @Autowired 107 @Autowired
@@ -359,7 +356,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -359,7 +356,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
359 }else { 356 }else {
360 streamTypeStr = "UDP"; 357 streamTypeStr = "UDP";
361 } 358 }
362 - logger.info("[上级点播] 平台:{}, 通道:{}, 收流地址:{}:{},收流方式:{}, ssrc:{}", username, channelId, addressStr, port, streamTypeStr, ssrc); 359 + logger.info("[上级Invite] {}, 平台:{}, 通道:{}, 收流地址:{}:{},收流方式:{}, ssrc:{}", sessionName, username, channelId, addressStr, port, streamTypeStr, ssrc);
363 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, 360 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
364 device.getDeviceId(), channelId, mediaTransmissionTCP, platform.isRtcp()); 361 device.getDeviceId(), channelId, mediaTransmissionTCP, platform.isRtcp());
365 362
@@ -380,10 +377,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -380,10 +377,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
380 377
381 Long finalStartTime = startTime; 378 Long finalStartTime = startTime;
382 Long finalStopTime = stopTime; 379 Long finalStopTime = stopTime;
383 - ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON) -> {  
384 - String app = responseJSON.getString("app");  
385 - String stream = responseJSON.getString("stream");  
386 - logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", app, stream); 380 + InviteErrorCallback<Object> hookEvent = (code, msg, data) -> {
  381 + StreamInfo streamInfo = (StreamInfo)data;
  382 + MediaServerItem mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
  383 + logger.info("[上级Invite]下级已经开始推流。 回复200OK(SDP), {}/{}", streamInfo.getApp(), streamInfo.getStream());
387 // * 0 等待设备推流上来 384 // * 0 等待设备推流上来
388 // * 1 下级已经推流,等待上级平台回复ack 385 // * 1 下级已经推流,等待上级平台回复ack
389 // * 2 推流中 386 // * 2 推流中
@@ -429,11 +426,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -429,11 +426,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
429 logger.error("[命令发送失败] 国标级联 回复SdpAck", e); 426 logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
430 } 427 }
431 }; 428 };
432 - SipSubscribe.Event errorEvent = ((event) -> { 429 + InviteErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
433 // 未知错误。直接转发设备点播的错误 430 // 未知错误。直接转发设备点播的错误
434 try { 431 try {
435 - Response response = getMessageFactory().createResponse(event.statusCode, evt.getRequest());  
436 - sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response); 432 + if (statusCode > 0) {
  433 + Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
  434 + sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
  435 + }
437 } catch (ParseException | SipException e) { 436 } catch (ParseException | SipException e) {
438 logger.error("未处理的异常 ", e); 437 logger.error("未处理的异常 ", e);
439 } 438 }
@@ -446,67 +445,70 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -446,67 +445,70 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
446 // 写入redis, 超时时回复 445 // 写入redis, 超时时回复
447 redisCatchStorage.updateSendRTPSever(sendRtpItem); 446 redisCatchStorage.updateSendRTPSever(sendRtpItem);
448 playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), 447 playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
449 - DateUtil.formatter.format(end), null, result -> {  
450 - if (result.getCode() != 0) {  
451 - logger.warn("录像回放失败");  
452 - if (result.getEvent() != null) {  
453 - errorEvent.response(result.getEvent());  
454 - } 448 + DateUtil.formatter.format(end),
  449 + (code, msg, data) -> {
  450 + if (code == InviteErrorCode.SUCCESS.getCode()){
  451 + hookEvent.run(code, msg, data);
  452 + }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){
  453 + logger.info("[录像回放]超时, 用户:{}, 通道:{}", username, channelId);
455 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); 454 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
456 - try {  
457 - responseAck(request, Response.REQUEST_TIMEOUT);  
458 - } catch (SipException | InvalidArgumentException | ParseException e) {  
459 - logger.error("[命令发送失败] 国标级联 录像回放 发送REQUEST_TIMEOUT: {}", e.getMessage());  
460 - }  
461 - } else {  
462 - if (result.getMediaServerItem() != null) {  
463 - hookEvent.response(result.getMediaServerItem(), result.getResponse());  
464 - } 455 + errorEvent.run(code, msg, data);
  456 + }else {
  457 + errorEvent.run(code, msg, data);
465 } 458 }
466 }); 459 });
467 - } else { 460 + }else if ("Download".equalsIgnoreCase(sessionName)) {
  461 + // 获取指定的下载速度
  462 + Vector sdpMediaDescriptions = sdp.getMediaDescriptions(true);
  463 + MediaDescription mediaDescription = null;
  464 + String downloadSpeed = "1";
  465 + if (sdpMediaDescriptions.size() > 0) {
  466 + mediaDescription = (MediaDescription)sdpMediaDescriptions.get(0);
  467 + }
  468 + if (mediaDescription != null) {
  469 + downloadSpeed = mediaDescription.getAttribute("downloadspeed");
  470 + }
  471 +
  472 + sendRtpItem.setPlayType(InviteStreamType.DOWNLOAD);
  473 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
  474 + sendRtpItem.setStreamId(ssrcInfo.getStream());
  475 + // 写入redis, 超时时回复
  476 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  477 + playService.download(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
  478 + DateUtil.formatter.format(end), Integer.parseInt(downloadSpeed),
  479 + (code, msg, data) -> {
  480 + if (code == InviteErrorCode.SUCCESS.getCode()){
  481 + hookEvent.run(code, msg, data);
  482 + }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){
  483 + logger.info("[录像下载]超时, 用户:{}, 通道:{}", username, channelId);
  484 + redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
  485 + errorEvent.run(code, msg, data);
  486 + }else {
  487 + errorEvent.run(code, msg, data);
  488 + }
  489 + });
  490 + }else {
468 sendRtpItem.setPlayType(InviteStreamType.PLAY); 491 sendRtpItem.setPlayType(InviteStreamType.PLAY);
469 - SsrcTransaction playTransaction = sessionManager.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);  
470 - if (playTransaction != null) {  
471 - Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, "rtp", playTransaction.getStream());  
472 - if (!streamReady) {  
473 - boolean hasRtpServer = mediaServerService.checkRtpServer(mediaServerItem, "rtp", playTransaction.getStream());  
474 - if (hasRtpServer) {  
475 - logger.info("[上级点播]已经开启rtpServer但是尚未收到流,开启监听流的到来");  
476 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", playTransaction.getStream(), true, "rtsp", mediaServerItem.getId());  
477 - zlmHttpHookSubscribe.addSubscribe(hookSubscribe, hookEvent);  
478 - }else {  
479 - playTransaction = null;  
480 - }  
481 - } 492 + String streamId = null;
  493 + if (mediaServerItem.isRtpEnable()) {
  494 + streamId = String.format("%s_%s", device.getDeviceId(), channelId);
  495 + }else {
  496 + streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
482 } 497 }
483 - if (playTransaction == null) {  
484 - // 被点播的通道目前未被点播,则开始点播  
485 - String streamId = null;  
486 - if (mediaServerItem.isRtpEnable()) {  
487 - streamId = String.format("%s_%s", device.getDeviceId(), channelId);  
488 - }  
489 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, ssrc, device.isSsrcCheck(), false, 0, false, device.getStreamModeForParam());  
490 - logger.info(JSONObject.toJSONString(ssrcInfo));  
491 - sendRtpItem.setStreamId(ssrcInfo.getStream());  
492 -// sendRtpItem.setSsrc(ssrcInfo.getSsrc());  
493 -  
494 - // 写入redis, 超时时回复  
495 - redisCatchStorage.updateSendRTPSever(sendRtpItem);  
496 - playService.play(mediaServerItem, ssrcInfo, device, channelId, hookEvent, errorEvent, (code, msg) -> { 498 + sendRtpItem.setStreamId(streamId);
  499 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  500 + playService.play(mediaServerItem, device.getDeviceId(), channelId, ((code, msg, data) -> {
  501 + if (code == InviteErrorCode.SUCCESS.getCode()){
  502 + hookEvent.run(code, msg, data);
  503 + }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){
497 logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId); 504 logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId);
498 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); 505 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
499 - });  
500 - } else { 506 + errorEvent.run(code, msg, data);
  507 + }else {
  508 + errorEvent.run(code, msg, data);
  509 + }
  510 + }));
501 511
502 - sendRtpItem.setStreamId(playTransaction.getStream());  
503 - // 写入redis, 超时时回复  
504 - redisCatchStorage.updateSendRTPSever(sendRtpItem);  
505 - JSONObject jsonObject = new JSONObject();  
506 - jsonObject.put("app", sendRtpItem.getApp());  
507 - jsonObject.put("stream", sendRtpItem.getStreamId());  
508 - hookEvent.response(mediaServerItem, jsonObject);  
509 - }  
510 } 512 }
511 } else if (gbStream != null) { 513 } else if (gbStream != null) {
512 514
@@ -559,7 +561,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -559,7 +561,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
559 int port, Boolean tcpActive, boolean mediaTransmissionTCP, 561 int port, Boolean tcpActive, boolean mediaTransmissionTCP,
560 String channelId, String addressStr, String ssrc, String requesterId) { 562 String channelId, String addressStr, String ssrc, String requesterId) {
561 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); 563 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
562 - if (streamReady) { 564 + if (streamReady != null && streamReady) {
563 // 自平台内容 565 // 自平台内容
564 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, 566 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
565 gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp()); 567 gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());
@@ -598,7 +600,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -598,7 +600,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
598 // 推流 600 // 推流
599 if (streamPushItem.isSelf()) { 601 if (streamPushItem.isSelf()) {
600 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); 602 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
601 - if (streamReady) { 603 + if (streamReady != null && streamReady) {
602 // 自平台内容 604 // 自平台内容
603 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, 605 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
604 gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp()); 606 gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -80,7 +80,6 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -80,7 +80,6 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
80 public void process(RequestEvent evt) { 80 public void process(RequestEvent evt) {
81 try { 81 try {
82 RequestEventExt evtExt = (RequestEventExt) evt; 82 RequestEventExt evtExt = (RequestEventExt) evt;
83 - String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();  
84 83
85 SIPRequest request = (SIPRequest)evt.getRequest(); 84 SIPRequest request = (SIPRequest)evt.getRequest();
86 Response response = null; 85 Response response = null;
@@ -91,12 +90,13 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -91,12 +90,13 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
91 AddressImpl address = (AddressImpl) fromHeader.getAddress(); 90 AddressImpl address = (AddressImpl) fromHeader.getAddress();
92 SipUri uri = (SipUri) address.getURI(); 91 SipUri uri = (SipUri) address.getURI();
93 String deviceId = uri.getUser(); 92 String deviceId = uri.getUser();
94 - logger.info("[注册请求] 设备:{}, 开始处理: {}", deviceId, requestAddress); 93 +
95 Device device = deviceService.getDevice(deviceId); 94 Device device = deviceService.getDevice(deviceId);
96 95
97 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, 96 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,
98 userSetting.getSipUseSourceIpAsRemoteAddress()); 97 userSetting.getSipUseSourceIpAsRemoteAddress());
99 - logger.info("[注册请求] 设备:{}, 远程地址为: {}:{}", deviceId, remoteAddressInfo.getIp(), remoteAddressInfo.getPort()); 98 + String requestAddress = remoteAddressInfo.getIp() + ":" + remoteAddressInfo.getPort();
  99 + logger.info("[注册请求] 设备:{}, 开始处理: {}", deviceId, requestAddress);
100 if (device != null && 100 if (device != null &&
101 device.getSipTransactionInfo() != null && 101 device.getSipTransactionInfo() != null &&
102 request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) { 102 request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info;
2 2
3 -import com.genersoft.iot.vmp.common.StreamInfo; 3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.gb28181.bean.*; 5 import com.genersoft.iot.vmp.gb28181.bean.*;
5 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 6 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 7 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
@@ -9,6 +10,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; @@ -9,6 +10,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
9 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; 10 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
10 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
11 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 12 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  13 +import com.genersoft.iot.vmp.service.IInviteStreamService;
12 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 14 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 15 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
14 import gov.nist.javax.sip.message.SIPRequest; 16 import gov.nist.javax.sip.message.SIPRequest;
@@ -17,10 +19,12 @@ import org.slf4j.LoggerFactory; @@ -17,10 +19,12 @@ import org.slf4j.LoggerFactory;
17 import org.springframework.beans.factory.InitializingBean; 19 import org.springframework.beans.factory.InitializingBean;
18 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.stereotype.Component; 21 import org.springframework.stereotype.Component;
  22 +
20 import javax.sip.InvalidArgumentException; 23 import javax.sip.InvalidArgumentException;
21 import javax.sip.RequestEvent; 24 import javax.sip.RequestEvent;
22 import javax.sip.SipException; 25 import javax.sip.SipException;
23 -import javax.sip.header.*; 26 +import javax.sip.header.CallIdHeader;
  27 +import javax.sip.header.ContentTypeHeader;
24 import javax.sip.message.Response; 28 import javax.sip.message.Response;
25 import java.text.ParseException; 29 import java.text.ParseException;
26 30
@@ -44,6 +48,9 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I @@ -44,6 +48,9 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I
44 private IRedisCatchStorage redisCatchStorage; 48 private IRedisCatchStorage redisCatchStorage;
45 49
46 @Autowired 50 @Autowired
  51 + private IInviteStreamService inviteStreamService;
  52 +
  53 + @Autowired
47 private IVideoManagerStorage storager; 54 private IVideoManagerStorage storager;
48 55
49 @Autowired 56 @Autowired
@@ -103,27 +110,30 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I @@ -103,27 +110,30 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I
103 if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) { 110 if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) {
104 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); 111 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
105 String streamId = sendRtpItem.getStreamId(); 112 String streamId = sendRtpItem.getStreamId();
106 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
107 - if (null == streamInfo) { 113 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  114 + if (null == inviteInfo) {
108 responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found"); 115 responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found");
109 return; 116 return;
110 } 117 }
111 - Device device1 = storager.queryVideoDevice(streamInfo.getDeviceID());  
112 - cmder.playbackControlCmd(device1,streamInfo,new String(evt.getRequest().getRawContent()),eventResult -> {  
113 - // 失败的回复  
114 - try {  
115 - responseAck(request, eventResult.statusCode, eventResult.msg);  
116 - } catch (SipException | InvalidArgumentException | ParseException e) {  
117 - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());  
118 - }  
119 - }, eventResult -> {  
120 - // 成功的回复  
121 - try {  
122 - responseAck(request, eventResult.statusCode);  
123 - } catch (SipException | InvalidArgumentException | ParseException e) {  
124 - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());  
125 - }  
126 - }); 118 + Device device1 = storager.queryVideoDevice(inviteInfo.getDeviceId());
  119 + if (inviteInfo.getStreamInfo() != null) {
  120 + cmder.playbackControlCmd(device1,inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()),eventResult -> {
  121 + // 失败的回复
  122 + try {
  123 + responseAck(request, eventResult.statusCode, eventResult.msg);
  124 + } catch (SipException | InvalidArgumentException | ParseException e) {
  125 + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
  126 + }
  127 + }, eventResult -> {
  128 + // 成功的回复
  129 + try {
  130 + responseAck(request, eventResult.statusCode);
  131 + } catch (SipException | InvalidArgumentException | ParseException e) {
  132 + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
  133 + }
  134 + });
  135 + }
  136 +
127 } 137 }
128 } 138 }
129 } catch (SipException e) { 139 } catch (SipException e) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
2 2
3 -import com.genersoft.iot.vmp.common.StreamInfo; 3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 5 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 import com.genersoft.iot.vmp.gb28181.bean.Device; 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 7 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
@@ -15,6 +16,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify. @@ -15,6 +16,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.
15 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 16 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
16 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; 17 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
17 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; 18 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  19 +import com.genersoft.iot.vmp.service.IInviteStreamService;
18 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
19 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 21 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
20 import gov.nist.javax.sip.message.SIPRequest; 22 import gov.nist.javax.sip.message.SIPRequest;
@@ -64,6 +66,12 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -64,6 +66,12 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
64 @Autowired 66 @Autowired
65 private ZlmHttpHookSubscribe subscribe; 67 private ZlmHttpHookSubscribe subscribe;
66 68
  69 + @Autowired
  70 + private IInviteStreamService inviteStreamService;
  71 +
  72 + @Autowired
  73 + private VideoStreamSessionManager streamSession;
  74 +
67 @Override 75 @Override
68 public void afterPropertiesSet() throws Exception { 76 public void afterPropertiesSet() throws Exception {
69 notifyMessageHandler.addHandler(cmdType, this); 77 notifyMessageHandler.addHandler(cmdType, this);
@@ -82,17 +90,15 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -82,17 +90,15 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
82 String NotifyType =getText(rootElement, "NotifyType"); 90 String NotifyType =getText(rootElement, "NotifyType");
83 if ("121".equals(NotifyType)){ 91 if ("121".equals(NotifyType)){
84 logger.info("[录像流]推送完毕,收到关流通知"); 92 logger.info("[录像流]推送完毕,收到关流通知");
85 - // 查询是设备  
86 - StreamInfo streamInfo = redisCatchStorage.queryDownload(null, null, null, callIdHeader.getCallId());  
87 - if (streamInfo != null) {  
88 - // 设置进度100%  
89 - streamInfo.setProgress(1);  
90 - redisCatchStorage.startDownload(streamInfo, callIdHeader.getCallId());  
91 - }  
92 93
93 - // 先从会话内查找  
94 - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);  
95 - if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题 94 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
  95 + if (ssrcTransaction != null) {
  96 + logger.info("[录像流]推送完毕,关流通知, device: {}, channelId: {}", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId());
  97 + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  98 + if (inviteInfo.getStreamInfo() != null) {
  99 + inviteInfo.getStreamInfo().setProgress(1);
  100 + inviteStreamService.updateInviteInfo(inviteInfo);
  101 + }
96 102
97 try { 103 try {
98 cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); 104 cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId());
@@ -117,6 +123,8 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -117,6 +123,8 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
117 logger.error("[命令发送失败] 国标级联 录像播放完毕: {}", e.getMessage()); 123 logger.error("[命令发送失败] 国标级联 录像播放完毕: {}", e.getMessage());
118 } 124 }
119 } 125 }
  126 + }else {
  127 + logger.info("[录像流]推送完毕,关流通知, 但是未找到对应的下载信息");
120 } 128 }
121 } 129 }
122 } 130 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.media.zlm; @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.media.zlm;
2 2
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.alibaba.fastjson2.JSONObject; 4 import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.InviteInfo;
  6 +import com.genersoft.iot.vmp.common.InviteSessionType;
5 import com.genersoft.iot.vmp.common.StreamInfo; 7 import com.genersoft.iot.vmp.common.StreamInfo;
6 import com.genersoft.iot.vmp.conf.UserSetting; 8 import com.genersoft.iot.vmp.conf.UserSetting;
7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 9 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
@@ -22,10 +24,8 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.*; @@ -22,10 +24,8 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
22 import com.genersoft.iot.vmp.service.*; 24 import com.genersoft.iot.vmp.service.*;
23 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 25 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
24 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 26 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
25 -import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx;  
26 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 27 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
27 import com.genersoft.iot.vmp.vmanager.bean.StreamContent; 28 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
28 -import com.genersoft.iot.vmp.vmanager.bean.WVPResult;  
29 import org.slf4j.Logger; 29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory; 30 import org.slf4j.LoggerFactory;
31 import org.springframework.beans.factory.annotation.Autowired; 31 import org.springframework.beans.factory.annotation.Autowired;
@@ -71,6 +71,9 @@ public class ZLMHttpHookListener { @@ -71,6 +71,9 @@ public class ZLMHttpHookListener {
71 private IRedisCatchStorage redisCatchStorage; 71 private IRedisCatchStorage redisCatchStorage;
72 72
73 @Autowired 73 @Autowired
  74 + private IInviteStreamService inviteStreamService;
  75 +
  76 + @Autowired
74 private IDeviceService deviceService; 77 private IDeviceService deviceService;
75 78
76 @Autowired 79 @Autowired
@@ -252,7 +255,7 @@ public class ZLMHttpHookListener { @@ -252,7 +255,7 @@ public class ZLMHttpHookListener {
252 result.setEnable_audio(deviceChannel.isHasAudio()); 255 result.setEnable_audio(deviceChannel.isHasAudio());
253 } 256 }
254 // 如果是录像下载就设置视频间隔十秒 257 // 如果是录像下载就设置视频间隔十秒
255 - if (ssrcTransactionForAll.get(0).getType() == VideoStreamSessionManager.SessionType.download) { 258 + if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) {
256 result.setMp4_max_second(10); 259 result.setMp4_max_second(10);
257 result.setEnable_audio(true); 260 result.setEnable_audio(true);
258 result.setEnable_mp4(true); 261 result.setEnable_mp4(true);
@@ -342,17 +345,10 @@ public class ZLMHttpHookListener { @@ -342,17 +345,10 @@ public class ZLMHttpHookListener {
342 } 345 }
343 346
344 if ("rtp".equals(param.getApp()) && !param.isRegist()) { 347 if ("rtp".equals(param.getApp()) && !param.isRegist()) {
345 - StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(param.getStream());  
346 - if (streamInfo != null) {  
347 - redisCatchStorage.stopPlay(streamInfo);  
348 - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());  
349 - } else {  
350 - streamInfo = redisCatchStorage.queryPlayback(null, null,  
351 - param.getStream(), null);  
352 - if (streamInfo != null) {  
353 - redisCatchStorage.stopPlayback(streamInfo.getDeviceID(), streamInfo.getChannelId(),  
354 - streamInfo.getStream(), null);  
355 - } 348 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
  349 + if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) {
  350 + inviteStreamService.removeInviteInfo(inviteInfo);
  351 + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
356 } 352 }
357 } else { 353 } else {
358 if (!"rtp".equals(param.getApp())) { 354 if (!"rtp".equals(param.getApp())) {
@@ -442,7 +438,7 @@ public class ZLMHttpHookListener { @@ -442,7 +438,7 @@ public class ZLMHttpHookListener {
442 @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") 438 @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8")
443 public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) { 439 public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) {
444 440
445 - logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), 441 + logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(),
446 param.getApp(), param.getStream()); 442 param.getApp(), param.getStream());
447 JSONObject ret = new JSONObject(); 443 JSONObject ret = new JSONObject();
448 ret.put("code", 0); 444 ret.put("code", 0);
@@ -450,13 +446,20 @@ public class ZLMHttpHookListener { @@ -450,13 +446,20 @@ public class ZLMHttpHookListener {
450 if ("rtp".equals(param.getApp())) { 446 if ("rtp".equals(param.getApp())) {
451 ret.put("close", userSetting.getStreamOnDemand()); 447 ret.put("close", userSetting.getStreamOnDemand());
452 // 国标流, 点播/录像回放/录像下载 448 // 国标流, 点播/录像回放/录像下载
453 - StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(param.getStream()); 449 +// StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(param.getStream());
  450 +
  451 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
454 // 点播 452 // 点播
455 - if (streamInfoForPlayCatch != null) { 453 + if (inviteInfo != null) {
  454 + // 录像下载
  455 + if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {
  456 + ret.put("close", false);
  457 + return ret;
  458 + }
456 // 收到无人观看说明流也没有在往上级推送 459 // 收到无人观看说明流也没有在往上级推送
457 - if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) { 460 + if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {
458 List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId( 461 List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(
459 - streamInfoForPlayCatch.getChannelId()); 462 + inviteInfo.getChannelId());
460 if (sendRtpItems.size() > 0) { 463 if (sendRtpItems.size() > 0) {
461 for (SendRtpItem sendRtpItem : sendRtpItems) { 464 for (SendRtpItem sendRtpItem : sendRtpItems) {
462 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); 465 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
@@ -470,49 +473,22 @@ public class ZLMHttpHookListener { @@ -470,49 +473,22 @@ public class ZLMHttpHookListener {
470 } 473 }
471 } 474 }
472 } 475 }
473 - Device device = deviceService.getDevice(streamInfoForPlayCatch.getDeviceID()); 476 + Device device = deviceService.getDevice(inviteInfo.getDeviceId());
474 if (device != null) { 477 if (device != null) {
475 try { 478 try {
476 - cmder.streamByeCmd(device, streamInfoForPlayCatch.getChannelId(),  
477 - streamInfoForPlayCatch.getStream(), null); 479 + if (inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()) != null) {
  480 + cmder.streamByeCmd(device, inviteInfo.getChannelId(),
  481 + inviteInfo.getStream(), null);
  482 + }
478 } catch (InvalidArgumentException | ParseException | SipException | 483 } catch (InvalidArgumentException | ParseException | SipException |
479 SsrcTransactionNotFoundException e) { 484 SsrcTransactionNotFoundException e) {
480 logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); 485 logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage());
481 } 486 }
482 } 487 }
483 488
484 - redisCatchStorage.stopPlay(streamInfoForPlayCatch);  
485 - storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());  
486 - return ret;  
487 - }  
488 - // 录像回放  
489 - StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null,  
490 - param.getStream(), null);  
491 - if (streamInfoForPlayBackCatch != null) {  
492 - if (streamInfoForPlayBackCatch.isPause()) {  
493 - ret.put("close", false);  
494 - } else {  
495 - Device device = deviceService.getDevice(streamInfoForPlayBackCatch.getDeviceID());  
496 - if (device != null) {  
497 - try {  
498 - cmder.streamByeCmd(device, streamInfoForPlayBackCatch.getChannelId(),  
499 - streamInfoForPlayBackCatch.getStream(), null);  
500 - } catch (InvalidArgumentException | ParseException | SipException |  
501 - SsrcTransactionNotFoundException e) {  
502 - logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage());  
503 - }  
504 - }  
505 - redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(),  
506 - streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null);  
507 - }  
508 - return ret;  
509 - }  
510 - // 录像下载  
511 - StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null,  
512 - param.getStream(), null);  
513 - // 进行录像下载时无人观看不断流  
514 - if (streamInfoForDownload != null) {  
515 - ret.put("close", false); 489 + inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(),
  490 + inviteInfo.getChannelId(), inviteInfo.getStream());
  491 + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
516 return ret; 492 return ret;
517 } 493 }
518 } else { 494 } else {
@@ -582,6 +558,7 @@ public class ZLMHttpHookListener { @@ -582,6 +558,7 @@ public class ZLMHttpHookListener {
582 return defaultResult; 558 return defaultResult;
583 } 559 }
584 logger.info("[ZLM HOOK] 流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); 560 logger.info("[ZLM HOOK] 流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
  561 +
585 RequestMessage msg = new RequestMessage(); 562 RequestMessage msg = new RequestMessage();
586 String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; 563 String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
587 boolean exist = resultHolder.exist(key, null); 564 boolean exist = resultHolder.exist(key, null);
@@ -589,31 +566,22 @@ public class ZLMHttpHookListener { @@ -589,31 +566,22 @@ public class ZLMHttpHookListener {
589 String uuid = UUID.randomUUID().toString(); 566 String uuid = UUID.randomUUID().toString();
590 msg.setId(uuid); 567 msg.setId(uuid);
591 DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); 568 DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
592 - DeferredResultEx<HookResult> deferredResultEx = new DeferredResultEx<>(result);  
593 569
594 result.onTimeout(() -> { 570 result.onTimeout(() -> {
595 - logger.info("点播接口等待超时"); 571 + logger.info("[ZLM HOOK] 自动点播, 等待超时");
596 // 释放rtpserver 572 // 释放rtpserver
597 msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); 573 msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
598 resultHolder.invokeResult(msg); 574 resultHolder.invokeResult(msg);
599 }); 575 });
600 - // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误  
601 - deferredResultEx.setFilter(result1 -> {  
602 - WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>) result1;  
603 - HookResult resultForEnd = new HookResult();  
604 - resultForEnd.setCode(wvpResult1.getCode());  
605 - resultForEnd.setMsg(wvpResult1.getMsg());  
606 - return resultForEnd;  
607 - });  
608 576
609 // 录像查询以channelId作为deviceId查询 577 // 录像查询以channelId作为deviceId查询
610 - resultHolder.put(key, uuid, deferredResultEx); 578 + resultHolder.put(key, uuid, result);
611 579
612 if (!exist) { 580 if (!exist) {
613 - playService.play(mediaInfo, deviceId, channelId, null, eventResult -> {  
614 - msg.setData(new HookResult(eventResult.statusCode, eventResult.msg)); 581 + playService.play(mediaInfo, deviceId, channelId, (code, message, data) -> {
  582 + msg.setData(new HookResult(code, message));
615 resultHolder.invokeResult(msg); 583 resultHolder.invokeResult(msg);
616 - }, null); 584 + });
617 } 585 }
618 return result; 586 return result;
619 } else { 587 } else {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
@@ -97,7 +97,8 @@ public class ZLMMediaListManager { @@ -97,7 +97,8 @@ public class ZLMMediaListManager {
97 public void sendStreamEvent(String app, String stream, String mediaServerId) { 97 public void sendStreamEvent(String app, String stream, String mediaServerId) {
98 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); 98 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
99 // 查看推流状态 99 // 查看推流状态
100 - if (zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream)) { 100 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream);
  101 + if (streamReady != null && streamReady) {
101 ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(app, stream); 102 ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(app, stream);
102 if (channelOnlineEventLister != null) { 103 if (channelOnlineEventLister != null) {
103 try { 104 try {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -293,11 +293,14 @@ public class ZLMRTPServerFactory { @@ -293,11 +293,14 @@ public class ZLMRTPServerFactory {
293 if (jsonObject.getInteger("code") == 0) { 293 if (jsonObject.getInteger("code") == 0) {
294 localPort = jsonObject.getInteger("port"); 294 localPort = jsonObject.getInteger("port");
295 HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, serverItem.getId()); 295 HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, serverItem.getId());
296 - // 订阅 zlm启动事件, 新的zlm也会从这里进入系统  
297 hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout, 296 hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout,
298 (MediaServerItem mediaServerItem, JSONObject response)->{ 297 (MediaServerItem mediaServerItem, JSONObject response)->{
299 logger.info("[上级点播] {}->监听端口到期继续保持监听", ssrc); 298 logger.info("[上级点播] {}->监听端口到期继续保持监听", ssrc);
300 - keepPort(serverItem, ssrc); 299 + int port = keepPort(serverItem, ssrc);
  300 + if (port == 0) {
  301 + logger.info("[上级点播] {}->监听端口失败,移除监听", ssrc);
  302 + hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
  303 + }
301 }); 304 });
302 logger.info("[上级点播] {}->监听端口: {}", ssrc, localPort); 305 logger.info("[上级点播] {}->监听端口: {}", ssrc, localPort);
303 }else { 306 }else {
@@ -330,6 +333,9 @@ public class ZLMRTPServerFactory { @@ -330,6 +333,9 @@ public class ZLMRTPServerFactory {
330 */ 333 */
331 public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) { 334 public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) {
332 JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtsp", streamId); 335 JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtsp", streamId);
  336 + if (mediaInfo.getInteger("code") == -2) {
  337 + return null;
  338 + }
333 return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")); 339 return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
334 } 340 }
335 341
@@ -338,8 +344,10 @@ public class ZLMRTPServerFactory { @@ -338,8 +344,10 @@ public class ZLMRTPServerFactory {
338 */ 344 */
339 public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) { 345 public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) {
340 JSONObject mediaInfo = zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId); 346 JSONObject mediaInfo = zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId);
341 - return mediaInfo != null && (mediaInfo.getInteger("code") == 0  
342 - 347 + if (mediaInfo == null || (mediaInfo.getInteger("code") == -2)) {
  348 + return null;
  349 + }
  350 + return (mediaInfo.getInteger("code") == 0
343 && mediaInfo.getJSONArray("data") != null 351 && mediaInfo.getJSONArray("data") != null
344 && mediaInfo.getJSONArray("data").size() > 0); 352 && mediaInfo.getJSONArray("data").size() > 0);
345 } 353 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java
@@ -98,7 +98,10 @@ public class ZlmHttpHookSubscribe { @@ -98,7 +98,10 @@ public class ZlmHttpHookSubscribe {
98 98
99 if (!CollectionUtils.isEmpty(entriesToRemove)) { 99 if (!CollectionUtils.isEmpty(entriesToRemove)) {
100 for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entriesToRemove) { 100 for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entriesToRemove) {
101 - entries.remove(entry); 101 + eventMap.remove(entry.getKey());
  102 + }
  103 + if (eventMap.size() == 0) {
  104 + allSubscribes.remove(hookSubscribe.getHookType());
102 } 105 }
103 } 106 }
104 107
@@ -134,9 +137,9 @@ public class ZlmHttpHookSubscribe { @@ -134,9 +137,9 @@ public class ZlmHttpHookSubscribe {
134 /** 137 /**
135 * 对订阅数据进行过期清理 138 * 对订阅数据进行过期清理
136 */ 139 */
137 - @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次 140 +// @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次
  141 + @Scheduled(fixedRate = 2 * 1000)
138 public void execute(){ 142 public void execute(){
139 -  
140 Instant instant = Instant.now().minusMillis(TimeUnit.MINUTES.toMillis(5)); 143 Instant instant = Instant.now().minusMillis(TimeUnit.MINUTES.toMillis(5));
141 int total = 0; 144 int total = 0;
142 for (HookType hookType : allSubscribes.keySet()) { 145 for (HookType hookType : allSubscribes.keySet()) {
src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service;
  2 +
  3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
  5 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  6 +
  7 +/**
  8 + * 记录国标点播的状态,包括实时预览,下载,录像回放
  9 + */
  10 +public interface IInviteStreamService {
  11 +
  12 + /**
  13 + * 更新点播的状态信息
  14 + */
  15 + void updateInviteInfo(InviteInfo inviteInfo);
  16 +
  17 + /**
  18 + * 获取点播的状态信息
  19 + */
  20 + InviteInfo getInviteInfo(InviteSessionType type,
  21 + String deviceId,
  22 + String channelId,
  23 + String stream);
  24 +
  25 + /**
  26 + * 移除点播的状态信息
  27 + */
  28 + void removeInviteInfo(InviteSessionType type,
  29 + String deviceId,
  30 + String channelId,
  31 + String stream);
  32 + /**
  33 + * 移除点播的状态信息
  34 + */
  35 + void removeInviteInfo(InviteInfo inviteInfo);
  36 + /**
  37 + * 移除点播的状态信息
  38 + */
  39 + void removeInviteInfoByDeviceAndChannel(InviteSessionType inviteSessionType, String deviceId, String channelId);
  40 +
  41 + /**
  42 + * 获取点播的状态信息
  43 + */
  44 + InviteInfo getInviteInfoByDeviceAndChannel(InviteSessionType type,
  45 + String deviceId,
  46 + String channelId);
  47 +
  48 + /**
  49 + * 获取点播的状态信息
  50 + */
  51 + InviteInfo getInviteInfoByStream(InviteSessionType type, String stream);
  52 +
  53 +
  54 + /**
  55 + * 添加一个invite回调
  56 + */
  57 + void once(InviteSessionType type, String deviceId, String channelId, String stream, InviteErrorCallback<Object> callback);
  58 +
  59 + /**
  60 + * 调用一个invite回调
  61 + */
  62 + void call(InviteSessionType type, String deviceId, String channelId, String stream, int code, String msg, Object data);
  63 +
  64 + /**
  65 + * 清空一个设备的所有invite信息
  66 + */
  67 + void clearInviteInfo(String deviceId);
  68 +}
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
1 package com.genersoft.iot.vmp.service; 1 package com.genersoft.iot.vmp.service;
2 2
3 -import com.alibaba.fastjson2.JSONObject;  
4 import com.genersoft.iot.vmp.common.StreamInfo; 3 import com.genersoft.iot.vmp.common.StreamInfo;
5 import com.genersoft.iot.vmp.conf.exception.ServiceException; 4 import com.genersoft.iot.vmp.conf.exception.ServiceException;
6 import com.genersoft.iot.vmp.gb28181.bean.Device; 5 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;  
9 -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;  
10 -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;  
11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 6 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 -import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;  
13 -import com.genersoft.iot.vmp.service.bean.PlayBackCallback; 7 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
14 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 8 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
15 9
16 import javax.sip.InvalidArgumentException; 10 import javax.sip.InvalidArgumentException;
@@ -22,12 +16,9 @@ import java.text.ParseException; @@ -22,12 +16,9 @@ import java.text.ParseException;
22 */ 16 */
23 public interface IPlayService { 17 public interface IPlayService {
24 18
25 - void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId);  
26 -  
27 void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 19 void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
28 - ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,  
29 - InviteTimeOutCallback timeoutCallback);  
30 - void play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent, Runnable timeoutCallback); 20 + InviteErrorCallback<Object> callback);
  21 + SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, InviteErrorCallback<Object> callback);
31 22
32 MediaServerItem getNewMediaServerItem(Device device); 23 MediaServerItem getNewMediaServerItem(Device device);
33 24
@@ -36,15 +27,13 @@ public interface IPlayService { @@ -36,15 +27,13 @@ public interface IPlayService {
36 */ 27 */
37 MediaServerItem getNewMediaServerItemHasAssist(Device device); 28 MediaServerItem getNewMediaServerItemHasAssist(Device device);
38 29
39 - void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String toString);  
40 -  
41 - void playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback);  
42 - void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); 30 + void playBack(String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
  31 + void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
43 32
44 void zlmServerOffline(String mediaServerId); 33 void zlmServerOffline(String mediaServerId);
45 34
46 - void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback);  
47 - void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); 35 + void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
  36 + void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
48 37
49 StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream); 38 StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
50 39
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCallback.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.bean;
  2 +
  3 +public interface InviteErrorCallback<T> {
  4 +
  5 + void run(int code, String msg, T data);
  6 +}
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.bean;
  2 +
  3 +/**
  4 + * 全局错误码
  5 + */
  6 +public enum InviteErrorCode {
  7 + SUCCESS(0, "成功"),
  8 + ERROR_FOR_SIGNALLING_TIMEOUT(-1, "信令超时"),
  9 + ERROR_FOR_STREAM_TIMEOUT(-2, "收流超时"),
  10 + ERROR_FOR_RESOURCE_EXHAUSTION(-3, "资源耗尽"),
  11 + ERROR_FOR_CATCH_DATA(-4, "缓存数据异常"),
  12 + ERROR_FOR_SIGNALLING_ERROR(-5, "收到信令错误"),
  13 + ERROR_FOR_STREAM_PARSING_EXCEPTIONS(-6, "流地址解析错误"),
  14 + ERROR_FOR_SDP_PARSING_EXCEPTIONS(-7, "SDP信息解析失败"),
  15 + ERROR_FOR_SSRC_UNAVAILABLE(-8, "SSRC不可用"),
  16 + ERROR_FOR_RESET_SSRC(-9, "重新设置收流信息失败"),
  17 + ERROR_FOR_SIP_SENDING_FAILED(-10, "命令发送失败"),
  18 + ERROR_FOR_ASSIST_NOT_READY(-11, "没有可用的assist服务"),
  19 + ERROR_FOR_PARAMETER_ERROR(-13, "参数异常");
  20 +
  21 + private final int code;
  22 + private final String msg;
  23 +
  24 + InviteErrorCode(int code, String msg) {
  25 + this.code = code;
  26 + this.msg = msg;
  27 + }
  28 +
  29 + public int getCode() {
  30 + return code;
  31 + }
  32 +
  33 + public String getMsg() {
  34 + return msg;
  35 + }
  36 +}
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
1 package com.genersoft.iot.vmp.service.impl; 1 package com.genersoft.iot.vmp.service.impl;
2 2
3 -import com.genersoft.iot.vmp.common.StreamInfo; 3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.gb28181.bean.Device; 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
5 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; 6 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
6 import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; 7 import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
7 import com.genersoft.iot.vmp.service.IDeviceChannelService; 8 import com.genersoft.iot.vmp.service.IDeviceChannelService;
  9 +import com.genersoft.iot.vmp.service.IInviteStreamService;
8 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 10 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
9 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; 11 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
10 import com.genersoft.iot.vmp.storager.dao.DeviceMapper; 12 import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
@@ -33,6 +35,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -33,6 +35,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
33 private IRedisCatchStorage redisCatchStorage; 35 private IRedisCatchStorage redisCatchStorage;
34 36
35 @Autowired 37 @Autowired
  38 + private IInviteStreamService inviteStreamService;
  39 +
  40 + @Autowired
36 private DeviceChannelMapper channelMapper; 41 private DeviceChannelMapper channelMapper;
37 42
38 @Autowired 43 @Autowired
@@ -78,9 +83,10 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -78,9 +83,10 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
78 public void updateChannel(String deviceId, DeviceChannel channel) { 83 public void updateChannel(String deviceId, DeviceChannel channel) {
79 String channelId = channel.getChannelId(); 84 String channelId = channel.getChannelId();
80 channel.setDeviceId(deviceId); 85 channel.setDeviceId(deviceId);
81 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);  
82 - if (streamInfo != null) {  
83 - channel.setStreamId(streamInfo.getStream()); 86 +// StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
  87 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  88 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  89 + channel.setStreamId(inviteInfo.getStreamInfo().getStream());
84 } 90 }
85 String now = DateUtil.getNow(); 91 String now = DateUtil.getNow();
86 channel.setUpdateTime(now); 92 channel.setUpdateTime(now);
@@ -106,9 +112,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -106,9 +112,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
106 if (channelList.size() == 0) { 112 if (channelList.size() == 0) {
107 for (DeviceChannel channel : channels) { 113 for (DeviceChannel channel : channels) {
108 channel.setDeviceId(deviceId); 114 channel.setDeviceId(deviceId);
109 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());  
110 - if (streamInfo != null) {  
111 - channel.setStreamId(streamInfo.getStream()); 115 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channel.getChannelId());
  116 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  117 + channel.setStreamId(inviteInfo.getStreamInfo().getStream());
112 } 118 }
113 String now = DateUtil.getNow(); 119 String now = DateUtil.getNow();
114 channel.setUpdateTime(now); 120 channel.setUpdateTime(now);
@@ -122,9 +128,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -122,9 +128,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
122 } 128 }
123 for (DeviceChannel channel : channels) { 129 for (DeviceChannel channel : channels) {
124 channel.setDeviceId(deviceId); 130 channel.setDeviceId(deviceId);
125 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());  
126 - if (streamInfo != null) {  
127 - channel.setStreamId(streamInfo.getStream()); 131 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channel.getChannelId());
  132 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  133 + channel.setStreamId(inviteInfo.getStreamInfo().getStream());
128 } 134 }
129 String now = DateUtil.getNow(); 135 String now = DateUtil.getNow();
130 channel.setUpdateTime(now); 136 channel.setUpdateTime(now);
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
12 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.service.IDeviceChannelService; 13 import com.genersoft.iot.vmp.service.IDeviceChannelService;
14 import com.genersoft.iot.vmp.service.IDeviceService; 14 import com.genersoft.iot.vmp.service.IDeviceService;
  15 +import com.genersoft.iot.vmp.service.IInviteStreamService;
15 import com.genersoft.iot.vmp.service.IMediaServerService; 16 import com.genersoft.iot.vmp.service.IMediaServerService;
16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 17 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
17 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; 18 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
@@ -59,6 +60,9 @@ public class DeviceServiceImpl implements IDeviceService { @@ -59,6 +60,9 @@ public class DeviceServiceImpl implements IDeviceService {
59 private IRedisCatchStorage redisCatchStorage; 60 private IRedisCatchStorage redisCatchStorage;
60 61
61 @Autowired 62 @Autowired
  63 + private IInviteStreamService inviteStreamService;
  64 +
  65 + @Autowired
62 private DeviceMapper deviceMapper; 66 private DeviceMapper deviceMapper;
63 67
64 @Autowired 68 @Autowired
@@ -97,7 +101,7 @@ public class DeviceServiceImpl implements IDeviceService { @@ -97,7 +101,7 @@ public class DeviceServiceImpl implements IDeviceService {
97 String now = DateUtil.getNow(); 101 String now = DateUtil.getNow();
98 if (deviceInRedis != null && deviceInDb == null) { 102 if (deviceInRedis != null && deviceInDb == null) {
99 // redis 存在脏数据 103 // redis 存在脏数据
100 - redisCatchStorage.clearCatchByDeviceId(device.getDeviceId()); 104 + inviteStreamService.clearInviteInfo(device.getDeviceId());
101 } 105 }
102 device.setUpdateTime(now); 106 device.setUpdateTime(now);
103 if (device.getKeepaliveIntervalTime() == 0) { 107 if (device.getKeepaliveIntervalTime() == 0) {
@@ -497,8 +501,10 @@ public class DeviceServiceImpl implements IDeviceService { @@ -497,8 +501,10 @@ public class DeviceServiceImpl implements IDeviceService {
497 node.setBasicData(channel); 501 node.setBasicData(channel);
498 node.setParent(false); 502 node.setParent(false);
499 if (channel.getChannelId().length() > 8) { 503 if (channel.getChannelId().length() > 8) {
500 - String gbCodeType = channel.getChannelId().substring(10, 13);  
501 - node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) ); 504 + if (channel.getChannelId().length() > 13) {
  505 + String gbCodeType = channel.getChannelId().substring(10, 13);
  506 + node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) );
  507 + }
502 }else { 508 }else {
503 node.setParent(true); 509 node.setParent(true);
504 } 510 }
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.impl;
  2 +
  3 +import com.alibaba.fastjson2.JSON;
  4 +import com.genersoft.iot.vmp.common.InviteInfo;
  5 +import com.genersoft.iot.vmp.common.InviteSessionStatus;
  6 +import com.genersoft.iot.vmp.common.InviteSessionType;
  7 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  8 +import com.genersoft.iot.vmp.service.IInviteStreamService;
  9 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  10 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
  13 +import org.springframework.beans.factory.annotation.Autowired;
  14 +import org.springframework.data.redis.core.RedisTemplate;
  15 +import org.springframework.stereotype.Service;
  16 +
  17 +import java.util.List;
  18 +import java.util.Map;
  19 +import java.util.concurrent.ConcurrentHashMap;
  20 +import java.util.concurrent.CopyOnWriteArrayList;
  21 +
  22 +@Service
  23 +public class InviteStreamServiceImpl implements IInviteStreamService {
  24 +
  25 + private final Logger logger = LoggerFactory.getLogger(InviteStreamServiceImpl.class);
  26 +
  27 + private final Map<String, List<InviteErrorCallback<Object>>> inviteErrorCallbackMap = new ConcurrentHashMap<>();
  28 +
  29 + @Autowired
  30 + private RedisTemplate<Object, Object> redisTemplate;
  31 +
  32 + @Override
  33 + public void updateInviteInfo(InviteInfo inviteInfo) {
  34 + if (inviteInfo == null || (inviteInfo.getDeviceId() == null || inviteInfo.getChannelId() == null)) {
  35 + logger.warn("[更新Invite信息],参数不全: {}", JSON.toJSON(inviteInfo));
  36 + return;
  37 + }
  38 + InviteInfo inviteInfoForUpdate = null;
  39 +
  40 + if (InviteSessionStatus.ready == inviteInfo.getStatus()) {
  41 + if (inviteInfo.getDeviceId() == null
  42 + || inviteInfo.getChannelId() == null
  43 + || inviteInfo.getType() == null
  44 + || inviteInfo.getStream() == null
  45 + ) {
  46 + return;
  47 + }
  48 + inviteInfoForUpdate = inviteInfo;
  49 + } else {
  50 + InviteInfo inviteInfoInRedis = getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(),
  51 + inviteInfo.getChannelId(), inviteInfo.getStream());
  52 + if (inviteInfoInRedis == null) {
  53 + logger.warn("[更新Invite信息],未从缓存中读取到Invite信息: deviceId: {}, channel: {}, stream: {}",
  54 + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
  55 + return;
  56 + }
  57 + if (inviteInfo.getStreamInfo() != null) {
  58 + inviteInfoInRedis.setStreamInfo(inviteInfo.getStreamInfo());
  59 + }
  60 + if (inviteInfo.getSsrcInfo() != null) {
  61 + inviteInfoInRedis.setSsrcInfo(inviteInfo.getSsrcInfo());
  62 + }
  63 + if (inviteInfo.getStreamMode() != null) {
  64 + inviteInfoInRedis.setStreamMode(inviteInfo.getStreamMode());
  65 + }
  66 + if (inviteInfo.getReceiveIp() != null) {
  67 + inviteInfoInRedis.setReceiveIp(inviteInfo.getReceiveIp());
  68 + }
  69 + if (inviteInfo.getReceivePort() != null) {
  70 + inviteInfoInRedis.setReceivePort(inviteInfo.getReceivePort());
  71 + }
  72 + if (inviteInfo.getStatus() != null) {
  73 + inviteInfoInRedis.setStatus(inviteInfo.getStatus());
  74 + }
  75 +
  76 + inviteInfoForUpdate = inviteInfoInRedis;
  77 +
  78 + }
  79 + String key = VideoManagerConstants.INVITE_PREFIX +
  80 + "_" + inviteInfoForUpdate.getType() +
  81 + "_" + inviteInfoForUpdate.getDeviceId() +
  82 + "_" + inviteInfoForUpdate.getChannelId() +
  83 + "_" + inviteInfoForUpdate.getStream();
  84 + redisTemplate.opsForValue().set(key, inviteInfoForUpdate);
  85 + }
  86 +
  87 + @Override
  88 + public InviteInfo getInviteInfo(InviteSessionType type, String deviceId, String channelId, String stream) {
  89 + String key = VideoManagerConstants.INVITE_PREFIX +
  90 + "_" + (type != null ? type : "*") +
  91 + "_" + (deviceId != null ? deviceId : "*") +
  92 + "_" + (channelId != null ? channelId : "*") +
  93 + "_" + (stream != null ? stream : "*");
  94 + List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
  95 + if (scanResult.size() != 1) {
  96 + return null;
  97 + }
  98 +
  99 + return (InviteInfo) redisTemplate.opsForValue().get(scanResult.get(0));
  100 + }
  101 +
  102 + @Override
  103 + public InviteInfo getInviteInfoByDeviceAndChannel(InviteSessionType type, String deviceId, String channelId) {
  104 + return getInviteInfo(type, deviceId, channelId, null);
  105 + }
  106 +
  107 + @Override
  108 + public InviteInfo getInviteInfoByStream(InviteSessionType type, String stream) {
  109 + return getInviteInfo(type, null, null, stream);
  110 + }
  111 +
  112 + @Override
  113 + public void removeInviteInfo(InviteSessionType type, String deviceId, String channelId, String stream) {
  114 + String scanKey = VideoManagerConstants.INVITE_PREFIX +
  115 + "_" + (type != null ? type : "*") +
  116 + "_" + (deviceId != null ? deviceId : "*") +
  117 + "_" + (channelId != null ? channelId : "*") +
  118 + "_" + (stream != null ? stream : "*");
  119 + List<Object> scanResult = RedisUtil.scan(redisTemplate, scanKey);
  120 + if (scanResult.size() > 0) {
  121 + for (Object keyObj : scanResult) {
  122 + String key = (String) keyObj;
  123 + InviteInfo inviteInfo = (InviteInfo) redisTemplate.opsForValue().get(key);
  124 + if (inviteInfo == null) {
  125 + continue;
  126 + }
  127 + redisTemplate.delete(key);
  128 + inviteErrorCallbackMap.remove(buildKey(type, deviceId, channelId, inviteInfo.getStream()));
  129 + }
  130 + }
  131 + }
  132 +
  133 + @Override
  134 + public void removeInviteInfoByDeviceAndChannel(InviteSessionType inviteSessionType, String deviceId, String channelId) {
  135 + removeInviteInfo(inviteSessionType, deviceId, channelId, null);
  136 + }
  137 +
  138 + @Override
  139 + public void removeInviteInfo(InviteInfo inviteInfo) {
  140 + removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
  141 + }
  142 +
  143 + @Override
  144 + public void once(InviteSessionType type, String deviceId, String channelId, String stream, InviteErrorCallback<Object> callback) {
  145 + String key = buildKey(type, deviceId, channelId, stream);
  146 + List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
  147 + if (callbacks == null) {
  148 + callbacks = new CopyOnWriteArrayList<>();
  149 + inviteErrorCallbackMap.put(key, callbacks);
  150 + }
  151 + callbacks.add(callback);
  152 +
  153 + }
  154 +
  155 + @Override
  156 + public void call(InviteSessionType type, String deviceId, String channelId, String stream, int code, String msg, Object data) {
  157 + String key = buildKey(type, deviceId, channelId, stream);
  158 + List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
  159 + if (callbacks == null) {
  160 + return;
  161 + }
  162 + for (InviteErrorCallback<Object> callback : callbacks) {
  163 + callback.run(code, msg, data);
  164 + }
  165 + inviteErrorCallbackMap.remove(key);
  166 + }
  167 +
  168 + private String buildKey(InviteSessionType type, String deviceId, String channelId, String stream) {
  169 + String key = type + "_" + deviceId + "_" + channelId;
  170 + // 如果ssrc未null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite
  171 + if (stream != null) {
  172 + key += ("_" + stream);
  173 + }
  174 + return key;
  175 + }
  176 +
  177 +
  178 + @Override
  179 + public void clearInviteInfo(String deviceId) {
  180 + removeInviteInfo(null, deviceId, null, null);
  181 + }
  182 +}
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
1 package com.genersoft.iot.vmp.service.impl; 1 package com.genersoft.iot.vmp.service.impl;
2 2
3 -import com.alibaba.fastjson2.JSON;  
4 import com.alibaba.fastjson2.JSONArray; 3 import com.alibaba.fastjson2.JSONArray;
5 import com.alibaba.fastjson2.JSONObject; 4 import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.InviteInfo;
  6 +import com.genersoft.iot.vmp.common.InviteSessionStatus;
  7 +import com.genersoft.iot.vmp.common.InviteSessionType;
6 import com.genersoft.iot.vmp.common.StreamInfo; 8 import com.genersoft.iot.vmp.common.StreamInfo;
7 import com.genersoft.iot.vmp.conf.DynamicTask; 9 import com.genersoft.iot.vmp.conf.DynamicTask;
8 import com.genersoft.iot.vmp.conf.UserSetting; 10 import com.genersoft.iot.vmp.conf.UserSetting;
@@ -14,28 +16,23 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; @@ -14,28 +16,23 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
14 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; 16 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
15 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 17 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
16 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 18 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
17 -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;  
18 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 19 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
19 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 20 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
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;
  23 +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
22 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 24 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
23 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; 25 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
24 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; 26 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
25 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 27 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
26 -import com.genersoft.iot.vmp.service.IDeviceService;  
27 -import com.genersoft.iot.vmp.service.IMediaServerService;  
28 -import com.genersoft.iot.vmp.service.IMediaService;  
29 -import com.genersoft.iot.vmp.service.IPlayService;  
30 -import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;  
31 -import com.genersoft.iot.vmp.service.bean.PlayBackCallback;  
32 -import com.genersoft.iot.vmp.service.bean.PlayBackResult; 28 +import com.genersoft.iot.vmp.service.*;
  29 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  30 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
33 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 31 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
34 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 32 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
35 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 33 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
36 import com.genersoft.iot.vmp.utils.DateUtil; 34 import com.genersoft.iot.vmp.utils.DateUtil;
37 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 35 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
38 -import com.genersoft.iot.vmp.vmanager.bean.WVPResult;  
39 import org.slf4j.Logger; 36 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory; 37 import org.slf4j.LoggerFactory;
41 import org.springframework.beans.factory.annotation.Autowired; 38 import org.springframework.beans.factory.annotation.Autowired;
@@ -73,12 +70,18 @@ public class PlayServiceImpl implements IPlayService { @@ -73,12 +70,18 @@ public class PlayServiceImpl implements IPlayService {
73 private IRedisCatchStorage redisCatchStorage; 70 private IRedisCatchStorage redisCatchStorage;
74 71
75 @Autowired 72 @Autowired
  73 + private IInviteStreamService inviteStreamService;
  74 +
  75 + @Autowired
76 private DeferredResultHolder resultHolder; 76 private DeferredResultHolder resultHolder;
77 77
78 @Autowired 78 @Autowired
79 private ZLMRESTfulUtils zlmresTfulUtils; 79 private ZLMRESTfulUtils zlmresTfulUtils;
80 80
81 @Autowired 81 @Autowired
  82 + private ZLMRTPServerFactory zlmrtpServerFactory;
  83 +
  84 + @Autowired
82 private AssistRESTfulUtils assistRESTfulUtils; 85 private AssistRESTfulUtils assistRESTfulUtils;
83 86
84 @Autowired 87 @Autowired
@@ -111,137 +114,126 @@ public class PlayServiceImpl implements IPlayService { @@ -111,137 +114,126 @@ public class PlayServiceImpl implements IPlayService {
111 114
112 115
113 @Override 116 @Override
114 - public void play(MediaServerItem mediaServerItem, String deviceId, String channelId,  
115 - ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,  
116 - Runnable timeoutCallback) { 117 + public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, InviteErrorCallback<Object> callback) {
117 if (mediaServerItem == null) { 118 if (mediaServerItem == null) {
118 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm"); 119 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm");
119 } 120 }
120 - String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;  
121 -  
122 - RequestMessage msg = new RequestMessage();  
123 - msg.setKey(key);  
124 121
125 Device device = redisCatchStorage.getDevice(deviceId); 122 Device device = redisCatchStorage.getDevice(deviceId);
126 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);  
127 -  
128 - if (streamInfo != null) {  
129 - String streamId = streamInfo.getStream();  
130 - if (streamId == null) {  
131 - WVPResult wvpResult = new WVPResult();  
132 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
133 - wvpResult.setMsg("点播失败, redis缓存streamId等于null");  
134 - msg.setData(wvpResult);  
135 - resultHolder.invokeAllResult(msg);  
136 - return;  
137 - }  
138 - String mediaServerId = streamInfo.getMediaServerId();  
139 - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);  
140 -  
141 - JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);  
142 - if (rtpInfo.getInteger("code") == 0) {  
143 - if (rtpInfo.getBoolean("exist")) {  
144 - int localPort = rtpInfo.getInteger("local_port");  
145 - if (localPort == 0) {  
146 - logger.warn("[点播],点播时发现rtpServer存在,但是尚未开始推流");  
147 - // 此时说明rtpServer已经创建但是流还没有推上来  
148 - WVPResult wvpResult = new WVPResult();  
149 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
150 - wvpResult.setMsg("点播已经在进行中,请稍候重试");  
151 - msg.setData(wvpResult);  
152 -  
153 - resultHolder.invokeAllResult(msg);  
154 - return;  
155 - } else {  
156 - WVPResult wvpResult = new WVPResult();  
157 - wvpResult.setCode(ErrorCode.SUCCESS.getCode());  
158 - wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());  
159 - wvpResult.setData(streamInfo);  
160 - msg.setData(wvpResult);  
161 - resultHolder.invokeAllResult(msg);  
162 - if (hookEvent != null) {  
163 - hookEvent.response(mediaServerItem, JSON.parseObject(JSON.toJSONString(streamInfo)));  
164 - }  
165 - }  
166 -  
167 - } else {  
168 - redisCatchStorage.stopPlay(streamInfo); 123 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  124 +
  125 + if (inviteInfo != null ) {
  126 + if (inviteInfo.getStreamInfo() == null) {
  127 + // 点播发起了但是尚未成功, 仅注册回调等待结果即可
  128 + inviteStreamService.once(InviteSessionType.PLAY, deviceId, channelId, null, callback);
  129 + return inviteInfo.getSsrcInfo();
  130 + }else {
  131 + StreamInfo streamInfo = inviteInfo.getStreamInfo();
  132 + String streamId = streamInfo.getStream();
  133 + if (streamId == null) {
  134 + callback.run(InviteErrorCode.ERROR_FOR_CATCH_DATA.getCode(), "点播失败, redis缓存streamId等于null", null);
  135 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  136 + InviteErrorCode.ERROR_FOR_CATCH_DATA.getCode(),
  137 + "点播失败, redis缓存streamId等于null",
  138 + null);
  139 + return inviteInfo.getSsrcInfo();
  140 + }
  141 + String mediaServerId = streamInfo.getMediaServerId();
  142 + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  143 +
  144 + Boolean ready = zlmrtpServerFactory.isStreamReady(mediaInfo, "rtp", streamId);
  145 + if (ready != null && ready) {
  146 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  147 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  148 + InviteErrorCode.SUCCESS.getCode(),
  149 + InviteErrorCode.SUCCESS.getMsg(),
  150 + streamInfo);
  151 + return inviteInfo.getSsrcInfo();
  152 + }else {
  153 + // 点播发起了但是尚未成功, 仅注册回调等待结果即可
  154 + inviteStreamService.once(InviteSessionType.PLAY, deviceId, channelId, null, callback);
169 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 155 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
170 - streamInfo = null; 156 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
171 } 157 }
172 - } else {  
173 - //zlm连接失败  
174 - redisCatchStorage.stopPlay(streamInfo);  
175 - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());  
176 - streamInfo = null;  
177 -  
178 } 158 }
179 } 159 }
180 - if (streamInfo == null) {  
181 - String streamId = null;  
182 - if (mediaServerItem.isRtpEnable()) {  
183 - streamId = String.format("%s_%s", device.getDeviceId(), channelId);  
184 - }  
185 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false, 0, false, device.getStreamModeForParam());  
186 - if (ssrcInfo == null) {  
187 - WVPResult wvpResult = new WVPResult();  
188 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
189 - wvpResult.setMsg("开启收流失败");  
190 - msg.setData(wvpResult);  
191 -  
192 - resultHolder.invokeAllResult(msg);  
193 - return;  
194 - }  
195 - play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response) -> {  
196 - if (hookEvent != null) {  
197 - hookEvent.response(mediaServerItem, response);  
198 - }  
199 - }, event -> {  
200 - // sip error错误  
201 - WVPResult wvpResult = new WVPResult();  
202 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
203 - wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));  
204 - msg.setData(wvpResult);  
205 - resultHolder.invokeAllResult(msg);  
206 - if (errorEvent != null) {  
207 - errorEvent.response(event);  
208 - }  
209 - }, (code, msgStr) -> {  
210 - // invite点播超时  
211 - WVPResult wvpResult = new WVPResult();  
212 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
213 - if (code == 0) {  
214 - wvpResult.setMsg("点播超时,请稍候重试");  
215 - } else if (code == 1) {  
216 - wvpResult.setMsg("收流超时,请稍候重试");  
217 - }  
218 - msg.setData(wvpResult);  
219 - // 回复之前所有的点播请求  
220 - resultHolder.invokeAllResult(msg);  
221 - }); 160 +
  161 + String streamId = null;
  162 + if (mediaServerItem.isRtpEnable()) {
  163 + streamId = String.format("%s_%s", device.getDeviceId(), channelId);
  164 + }
  165 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false, 0, false, device.getStreamModeForParam());
  166 + if (ssrcInfo == null) {
  167 + callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getMsg(), null);
  168 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  169 + InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(),
  170 + InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getMsg(),
  171 + null);
  172 + return null;
222 } 173 }
  174 + // TODO 记录点播的状态
  175 + play(mediaServerItem, ssrcInfo, device, channelId, callback);
  176 + return ssrcInfo;
223 } 177 }
224 178
225 179
226 @Override 180 @Override
227 public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 181 public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
228 - ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,  
229 - InviteTimeOutCallback timeoutCallback) { 182 + InviteErrorCallback<Object> callback) {
230 183
  184 + if (mediaServerItem == null || ssrcInfo == null) {
  185 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  186 + InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
  187 + null);
  188 + return;
  189 + }
231 logger.info("[点播开始] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); 190 logger.info("[点播开始] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  191 +
  192 + //端口获取失败的ssrcInfo 没有必要发送点播指令
  193 + if (ssrcInfo.getPort() <= 0) {
  194 + logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo);
  195 + // 释放ssrc
  196 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  197 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  198 +
  199 + callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null);
  200 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  201 + InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null);
  202 + return;
  203 + }
  204 +
  205 + // 初始化redis中的invite消息状态
  206 + InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  207 + mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY,
  208 + InviteSessionStatus.ready);
  209 + inviteStreamService.updateInviteInfo(inviteInfo);
232 // 超时处理 210 // 超时处理
233 String timeOutTaskKey = UUID.randomUUID().toString(); 211 String timeOutTaskKey = UUID.randomUUID().toString();
234 dynamicTask.startDelay(timeOutTaskKey, () -> { 212 dynamicTask.startDelay(timeOutTaskKey, () -> {
235 // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况 213 // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况
236 - if (redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId) == null) { 214 + InviteInfo inviteInfoForTimeOut = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
  215 + if (inviteInfoForTimeOut == null || inviteInfoForTimeOut.getStreamInfo() == null) {
237 logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc()); 216 logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc());
238 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 217 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
  218 +// InviteInfo inviteInfoForTimeout = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.play, device.getDeviceId(), channelId);
  219 +// if (inviteInfoForTimeout == null) {
  220 +// return;
  221 +// }
  222 +// if (InviteSessionStatus.ok == inviteInfoForTimeout.getStatus() ) {
  223 +// // TODO 发送bye
  224 +// }else {
  225 +// // TODO 发送cancel
  226 +// }
  227 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
  228 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  229 + InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
  230 +
  231 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
239 try { 232 try {
240 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); 233 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null);
241 } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { 234 } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
242 logger.error("[点播超时], 发送BYE失败 {}", e.getMessage()); 235 logger.error("[点播超时], 发送BYE失败 {}", e.getMessage());
243 } finally { 236 } finally {
244 - timeoutCallback.run(1, "收流超时");  
245 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 237 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
246 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); 238 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
247 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 239 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
@@ -252,28 +244,26 @@ public class PlayServiceImpl implements IPlayService { @@ -252,28 +244,26 @@ public class PlayServiceImpl implements IPlayService {
252 } 244 }
253 } 245 }
254 }, userSetting.getPlayTimeout()); 246 }, userSetting.getPlayTimeout());
255 - //端口获取失败的ssrcInfo 没有必要发送点播指令  
256 - if (ssrcInfo.getPort() <= 0) {  
257 - logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo);  
258 - dynamicTask.stop(timeOutTaskKey);  
259 - // 释放ssrc  
260 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
261 - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());  
262 247
263 - RequestMessage msg = new RequestMessage();  
264 - msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + device.getDeviceId() + channelId);  
265 - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "点播端口分配异常"));  
266 - resultHolder.invokeAllResult(msg);  
267 - return;  
268 - }  
269 try { 248 try {
270 cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { 249 cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
271 logger.info("收到订阅消息: " + response.toJSONString()); 250 logger.info("收到订阅消息: " + response.toJSONString());
272 dynamicTask.stop(timeOutTaskKey); 251 dynamicTask.stop(timeOutTaskKey);
273 -  
274 // hook响应 252 // hook响应
275 - onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId);  
276 - hookEvent.response(mediaServerItemInuse, response); 253 + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId);
  254 + if (streamInfo == null){
  255 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  256 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  257 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  258 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  259 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  260 + return;
  261 + }
  262 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  263 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  264 + InviteErrorCode.SUCCESS.getCode(),
  265 + InviteErrorCode.SUCCESS.getMsg(),
  266 + streamInfo);
277 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); 267 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
278 String streamUrl; 268 String streamUrl;
279 if (mediaServerItemInuse.getRtspPort() != 0) { 269 if (mediaServerItemInuse.getRtspPort() != 0) {
@@ -288,6 +278,8 @@ public class PlayServiceImpl implements IPlayService { @@ -288,6 +278,8 @@ public class PlayServiceImpl implements IPlayService {
288 zlmresTfulUtils.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName); 278 zlmresTfulUtils.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName);
289 279
290 }, (event) -> { 280 }, (event) -> {
  281 + inviteInfo.setStatus(InviteSessionStatus.ok);
  282 +
291 ResponseEvent responseEvent = (ResponseEvent) event.event; 283 ResponseEvent responseEvent = (ResponseEvent) event.event;
292 String contentString = new String(responseEvent.getResponse().getRawContent()); 284 String contentString = new String(responseEvent.getResponse().getRawContent());
293 // 获取ssrc 285 // 获取ssrc
@@ -319,6 +311,18 @@ public class PlayServiceImpl implements IPlayService { @@ -319,6 +311,18 @@ public class PlayServiceImpl implements IPlayService {
319 logger.info("[点播-TCP主动连接对方] 结果: {}", jsonObject); 311 logger.info("[点播-TCP主动连接对方] 结果: {}", jsonObject);
320 } catch (SdpException e) { 312 } catch (SdpException e) {
321 logger.error("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e); 313 logger.error("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
  314 + dynamicTask.stop(timeOutTaskKey);
  315 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
  316 + // 释放ssrc
  317 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  318 +
  319 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  320 +
  321 + callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  322 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  323 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  324 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  325 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
322 } 326 }
323 } 327 }
324 return; 328 return;
@@ -332,9 +336,13 @@ public class PlayServiceImpl implements IPlayService { @@ -332,9 +336,13 @@ public class PlayServiceImpl implements IPlayService {
332 // 释放ssrc 336 // 释放ssrc
333 ssrcFactory.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 337 ssrcFactory.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
334 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 338 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
335 - event.msg = "下级自定义了ssrc,但是此ssrc不可用";  
336 - event.statusCode = 400;  
337 - errorEvent.response(event); 339 +
  340 + callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  341 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  342 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  343 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  344 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  345 +
338 return; 346 return;
339 } 347 }
340 // 单端口模式streamId也有变化,重新设置监听即可 348 // 单端口模式streamId也有变化,重新设置监听即可
@@ -342,27 +350,40 @@ public class PlayServiceImpl implements IPlayService { @@ -342,27 +350,40 @@ public class PlayServiceImpl implements IPlayService {
342 // 添加订阅 350 // 添加订阅
343 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); 351 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
344 subscribe.removeSubscribe(hookSubscribe); 352 subscribe.removeSubscribe(hookSubscribe);
345 - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); 353 + String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
  354 + hookSubscribe.getContent().put("stream", stream);
  355 + inviteInfo.setStream(stream);
346 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> { 356 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
347 logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); 357 logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
348 dynamicTask.stop(timeOutTaskKey); 358 dynamicTask.stop(timeOutTaskKey);
349 // hook响应 359 // hook响应
350 - onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId);  
351 - hookEvent.response(mediaServerItemInUse, response); 360 + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId);
  361 + if (streamInfo == null){
  362 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  363 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  364 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  365 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  366 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  367 + return;
  368 + }
  369 + callback.run(InviteErrorCode.SUCCESS.getCode(),
  370 + InviteErrorCode.SUCCESS.getMsg(), null);
  371 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  372 + InviteErrorCode.SUCCESS.getCode(),
  373 + InviteErrorCode.SUCCESS.getMsg(),
  374 + streamInfo);
352 }); 375 });
353 return; 376 return;
354 } 377 }
355 378
356 -  
357 // 更新ssrc 379 // 更新ssrc
358 Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse); 380 Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
359 if (!result) { 381 if (!result) {
360 try { 382 try {
361 - logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId); 383 + logger.warn("[点播] 更新ssrc失败,停止点播 {}/{}", device.getDeviceId(), channelId);
362 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null); 384 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
363 } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { 385 } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
364 logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage()); 386 logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
365 - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());  
366 } 387 }
367 388
368 dynamicTask.stop(timeOutTaskKey); 389 dynamicTask.stop(timeOutTaskKey);
@@ -370,14 +391,23 @@ public class PlayServiceImpl implements IPlayService { @@ -370,14 +391,23 @@ public class PlayServiceImpl implements IPlayService {
370 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 391 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
371 392
372 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 393 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
373 - event.msg = "下级自定义了ssrc,重新设置收流信息失败";  
374 - event.statusCode = 500;  
375 - errorEvent.response(event); 394 +
  395 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  396 + "下级自定义了ssrc,重新设置收流信息失败", null);
  397 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  398 + InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  399 + "下级自定义了ssrc,重新设置收流信息失败", null);
  400 +
  401 + }else {
  402 + ssrcInfo.setSsrc(ssrcInResponse);
  403 + inviteInfo.setSsrcInfo(ssrcInfo);
  404 + inviteInfo.setStream(ssrcInfo.getStream());
376 } 405 }
377 }else { 406 }else {
378 logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正"); 407 logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
379 } 408 }
380 } 409 }
  410 + inviteStreamService.updateInviteInfo(inviteInfo);
381 }, (event) -> { 411 }, (event) -> {
382 dynamicTask.stop(timeOutTaskKey); 412 dynamicTask.stop(timeOutTaskKey);
383 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); 413 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
@@ -385,7 +415,14 @@ public class PlayServiceImpl implements IPlayService { @@ -385,7 +415,14 @@ public class PlayServiceImpl implements IPlayService {
385 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 415 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
386 416
387 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 417 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
388 - errorEvent.response(event); 418 +
  419 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(),
  420 + String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null);
  421 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  422 + InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  423 + String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null);
  424 +
  425 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
389 }); 426 });
390 } catch (InvalidArgumentException | SipException | ParseException e) { 427 } catch (InvalidArgumentException | SipException | ParseException e) {
391 428
@@ -396,65 +433,57 @@ public class PlayServiceImpl implements IPlayService { @@ -396,65 +433,57 @@ public class PlayServiceImpl implements IPlayService {
396 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 433 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
397 434
398 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 435 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
399 - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();  
400 - eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent;  
401 - eventResult.statusCode = -1;  
402 - eventResult.msg = "命令发送失败";  
403 - errorEvent.response(eventResult); 436 +
  437 + callback.run(InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
  438 + InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
  439 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  440 + InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
  441 + InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
  442 +
  443 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
404 } 444 }
405 } 445 }
406 446
407 - @Override  
408 - public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId) { 447 + private StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId) {
409 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); 448 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
410 - RequestMessage msg = new RequestMessage();  
411 - msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId);  
412 if (streamInfo != null) { 449 if (streamInfo != null) {
413 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); 450 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
414 if (deviceChannel != null) { 451 if (deviceChannel != null) {
415 deviceChannel.setStreamId(streamInfo.getStream()); 452 deviceChannel.setStreamId(streamInfo.getStream());
416 storager.startPlay(deviceId, channelId, streamInfo.getStream()); 453 storager.startPlay(deviceId, channelId, streamInfo.getStream());
417 } 454 }
418 - redisCatchStorage.startPlay(streamInfo);  
419 -  
420 - WVPResult wvpResult = new WVPResult();  
421 - wvpResult.setCode(ErrorCode.SUCCESS.getCode());  
422 - wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());  
423 - wvpResult.setData(streamInfo);  
424 -  
425 - msg.setData(wvpResult);  
426 - resultHolder.invokeAllResult(msg);  
427 -  
428 - } else {  
429 - logger.warn("设备预览API调用失败!");  
430 - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "设备预览API调用失败!"));  
431 - resultHolder.invokeAllResult(msg); 455 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  456 + if (inviteInfo != null) {
  457 + inviteInfo.setStatus(InviteSessionStatus.ok);
  458 + inviteInfo.setStreamInfo(streamInfo);
  459 + inviteStreamService.updateInviteInfo(inviteInfo);
  460 + }
432 } 461 }
  462 + return streamInfo;
  463 +
433 } 464 }
434 465
435 - private void onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, PlayBackCallback playBackCallback) { 466 + private StreamInfo onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String startTime, String endTime) {
436 467
437 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); 468 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
438 - PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>();  
439 if (streamInfo != null) { 469 if (streamInfo != null) {
  470 + streamInfo.setStartTime(startTime);
  471 + streamInfo.setEndTime(endTime);
440 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); 472 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
441 if (deviceChannel != null) { 473 if (deviceChannel != null) {
442 deviceChannel.setStreamId(streamInfo.getStream()); 474 deviceChannel.setStreamId(streamInfo.getStream());
443 storager.startPlay(deviceId, channelId, streamInfo.getStream()); 475 storager.startPlay(deviceId, channelId, streamInfo.getStream());
444 } 476 }
445 - redisCatchStorage.startPlay(streamInfo); 477 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, deviceId, channelId);
  478 + if (inviteInfo != null) {
  479 + inviteInfo.setStatus(InviteSessionStatus.ok);
446 480
  481 + inviteInfo.setStreamInfo(streamInfo);
  482 + inviteStreamService.updateInviteInfo(inviteInfo);
  483 + }
447 484
448 - playBackResult.setCode(ErrorCode.SUCCESS.getCode());  
449 - playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());  
450 - playBackResult.setData(streamInfo);  
451 - playBackCallback.call(playBackResult);  
452 - } else {  
453 - logger.warn("录像回放调用失败!");  
454 - playBackResult.setCode(ErrorCode.ERROR100.getCode());  
455 - playBackResult.setMsg("录像回放调用失败!");  
456 - playBackCallback.call(playBackResult);  
457 } 485 }
  486 + return streamInfo;
458 } 487 }
459 488
460 @Override 489 @Override
@@ -493,23 +522,24 @@ public class PlayServiceImpl implements IPlayService { @@ -493,23 +522,24 @@ public class PlayServiceImpl implements IPlayService {
493 522
494 @Override 523 @Override
495 public void playBack(String deviceId, String channelId, String startTime, 524 public void playBack(String deviceId, String channelId, String startTime,
496 - String endTime, InviteStreamCallback inviteStreamCallback,  
497 - PlayBackCallback callback) { 525 + String endTime, InviteErrorCallback<Object> callback) {
498 Device device = storager.queryVideoDevice(deviceId); 526 Device device = storager.queryVideoDevice(deviceId);
499 if (device == null) { 527 if (device == null) {
500 return; 528 return;
501 } 529 }
502 MediaServerItem newMediaServerItem = getNewMediaServerItem(device); 530 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
503 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); 531 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
504 - playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback); 532 + playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, callback);
505 } 533 }
506 534
507 @Override 535 @Override
508 public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, 536 public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
509 String deviceId, String channelId, String startTime, 537 String deviceId, String channelId, String startTime,
510 - String endTime, InviteStreamCallback infoCallBack,  
511 - PlayBackCallback playBackCallback) { 538 + String endTime, InviteErrorCallback<Object> callback) {
512 if (mediaServerItem == null || ssrcInfo == null) { 539 if (mediaServerItem == null || ssrcInfo == null) {
  540 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  541 + InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
  542 + null);
513 return; 543 return;
514 } 544 }
515 545
@@ -517,132 +547,169 @@ public class PlayServiceImpl implements IPlayService { @@ -517,132 +547,169 @@ public class PlayServiceImpl implements IPlayService {
517 if (device == null) { 547 if (device == null) {
518 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在"); 548 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在");
519 } 549 }
520 - logger.info("[回放消息] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());  
521 - PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>(); 550 + logger.info("[录像回放] deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
  551 + device.getDeviceId(), channelId, startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(),
  552 + ssrcInfo.getSsrc(), device.isSsrcCheck());
  553 + // 初始化redis中的invite消息状态
  554 + InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  555 + mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK,
  556 + InviteSessionStatus.ready);
  557 + inviteStreamService.updateInviteInfo(inviteInfo);
522 String playBackTimeOutTaskKey = UUID.randomUUID().toString(); 558 String playBackTimeOutTaskKey = UUID.randomUUID().toString();
523 dynamicTask.startDelay(playBackTimeOutTaskKey, () -> { 559 dynamicTask.startDelay(playBackTimeOutTaskKey, () -> {
524 - logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));  
525 - playBackResult.setCode(ErrorCode.ERROR100.getCode());  
526 - playBackResult.setMsg("回放超时"); 560 + logger.warn("[录像回放] 超时,deviceId:{} ,channelId:{}", deviceId, channelId);
  561 + inviteStreamService.removeInviteInfo(inviteInfo);
  562 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null);
527 563
528 try { 564 try {
529 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); 565 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null);
530 } catch (InvalidArgumentException | ParseException | SipException e) { 566 } catch (InvalidArgumentException | ParseException | SipException e) {
531 - logger.error("[录像流]回放超时 发送BYE失败 {}", e.getMessage()); 567 + logger.error("[录像回放] 超时 发送BYE失败 {}", e.getMessage());
532 } catch (SsrcTransactionNotFoundException e) { 568 } catch (SsrcTransactionNotFoundException e) {
533 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 569 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
534 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 570 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
535 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); 571 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
536 streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); 572 streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
537 } 573 }
538 - // 回复之前所有的点播请求  
539 - playBackCallback.call(playBackResult);  
540 }, userSetting.getPlayTimeout()); 574 }, userSetting.getPlayTimeout());
541 575
542 SipSubscribe.Event errorEvent = event -> { 576 SipSubscribe.Event errorEvent = event -> {
  577 + logger.info("[录像回放] 失败,{} {}", event.statusCode, event.msg);
543 dynamicTask.stop(playBackTimeOutTaskKey); 578 dynamicTask.stop(playBackTimeOutTaskKey);
544 - playBackResult.setCode(ErrorCode.ERROR100.getCode());  
545 - playBackResult.setMsg(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));  
546 - playBackResult.setEvent(event);  
547 - playBackCallback.call(playBackResult); 579 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(),
  580 + String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg), null);
  581 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  582 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
548 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 583 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  584 + inviteStreamService.removeInviteInfo(inviteInfo);
549 }; 585 };
550 586
551 - InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {  
552 - logger.info("收到回放订阅消息: " + inviteStreamInfo.getResponse().toJSONString()); 587 + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> {
  588 + logger.info("收到回放订阅消息: " + jsonObject);
553 dynamicTask.stop(playBackTimeOutTaskKey); 589 dynamicTask.stop(playBackTimeOutTaskKey);
554 - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); 590 + StreamInfo streamInfo = onPublishHandlerForPlayback(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime);
555 if (streamInfo == null) { 591 if (streamInfo == null) {
556 logger.warn("设备回放API调用失败!"); 592 logger.warn("设备回放API调用失败!");
557 - playBackResult.setCode(ErrorCode.ERROR100.getCode());  
558 - playBackResult.setMsg("设备回放API调用失败!");  
559 - playBackCallback.call(playBackResult); 593 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  594 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
560 return; 595 return;
561 } 596 }
562 - redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());  
563 - playBackResult.setCode(ErrorCode.SUCCESS.getCode());  
564 - playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());  
565 - playBackResult.setData(streamInfo);  
566 - playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());  
567 - playBackResult.setResponse(inviteStreamInfo.getResponse());  
568 - playBackCallback.call(playBackResult); 597 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  598 + logger.info("[录像回放] 成功 deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}", device.getDeviceId(), channelId, startTime, endTime);
569 }; 599 };
570 600
571 try { 601 try {
572 - cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack, 602 + cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime,
573 hookEvent, eventResult -> { 603 hookEvent, eventResult -> {
574 - if (eventResult.type == SipSubscribe.EventResultType.response) {  
575 - ResponseEvent responseEvent = (ResponseEvent) eventResult.event;  
576 - String contentString = new String(responseEvent.getResponse().getRawContent());  
577 - // 获取ssrc  
578 - int ssrcIndex = contentString.indexOf("y=");  
579 - // 检查是否有y字段  
580 - if (ssrcIndex >= 0) {  
581 - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容  
582 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
583 - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理  
584 - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {  
585 - return;  
586 - }  
587 - logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);  
588 - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {  
589 - logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);  
590 -  
591 - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {  
592 - // ssrc 不可用  
593 - // 释放ssrc 604 + inviteInfo.setStatus(InviteSessionStatus.ok);
  605 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
  606 + String contentString = new String(responseEvent.getResponse().getRawContent());
  607 + // 获取ssrc
  608 + int ssrcIndex = contentString.indexOf("y=");
  609 + // 检查是否有y字段
  610 + if (ssrcIndex >= 0) {
  611 + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  612 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  613 + // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  614 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  615 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  616 + String substring = contentString.substring(0, contentString.indexOf("y="));
  617 + try {
  618 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  619 + int port = -1;
  620 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  621 + for (Object description : mediaDescriptions) {
  622 + MediaDescription mediaDescription = (MediaDescription) description;
  623 + Media media = mediaDescription.getMedia();
  624 +
  625 + Vector mediaFormats = media.getMediaFormats(false);
  626 + if (mediaFormats.contains("96")) {
  627 + port = media.getMediaPort();
  628 + break;
  629 + }
  630 + }
  631 + logger.info("[录像回放-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  632 + JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
  633 + logger.info("[录像回放-TCP主动连接对方] 结果: {}", jsonObject);
  634 + } catch (SdpException e) {
  635 + logger.error("[录像回放-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
594 dynamicTask.stop(playBackTimeOutTaskKey); 636 dynamicTask.stop(playBackTimeOutTaskKey);
  637 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
  638 + // 释放ssrc
595 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 639 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  640 +
596 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 641 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
597 - eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用";  
598 - eventResult.statusCode = 400;  
599 - errorEvent.response(eventResult);  
600 - return; 642 +
  643 + callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  644 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  645 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  646 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  647 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
601 } 648 }
  649 + }
  650 + return;
  651 + }
  652 + logger.info("[录像回放] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  653 + if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
  654 + logger.info("[录像回放] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  655 +
  656 + if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
  657 + // ssrc 不可用
  658 + logger.info("[录像回放] SSRC修正时发现ssrc不可使用 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  659 + // 释放ssrc
  660 + dynamicTask.stop(playBackTimeOutTaskKey);
  661 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  662 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  663 + callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  664 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  665 + return;
  666 + }
  667 +
  668 + // 单端口模式streamId也有变化,需要重新设置监听
  669 + if (!mediaServerItem.isRtpEnable()) {
  670 + // 添加订阅
  671 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  672 + subscribe.removeSubscribe(hookSubscribe);
  673 + String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
  674 + hookSubscribe.getContent().put("stream", stream);
  675 + inviteInfo.setStream(stream);
  676 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
  677 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  678 + dynamicTask.stop(playBackTimeOutTaskKey);
  679 + // hook响应
  680 + hookEvent.response(mediaServerItemInUse, response);
  681 + });
  682 + }
  683 + // 更新ssrc
  684 + Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
  685 + if (!result) {
  686 + try {
  687 + logger.warn("[录像回放] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);
  688 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  689 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  690 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
602 691
603 - // 单端口模式streamId也有变化,需要重新设置监听  
604 - if (!mediaServerItem.isRtpEnable()) {  
605 - // 添加订阅  
606 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
607 - subscribe.removeSubscribe(hookSubscribe);  
608 - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());  
609 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {  
610 - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());  
611 - dynamicTask.stop(playBackTimeOutTaskKey);  
612 - // hook响应  
613 - onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, playBackCallback);  
614 - hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));  
615 - });  
616 } 692 }
617 693
618 - // 关闭rtp server  
619 - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{  
620 - if (result) {  
621 - // 重新开启ssrc server  
622 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), true, device.getStreamModeForParam());  
623 - }else {  
624 - try {  
625 - logger.warn("[回放消息]停止 {}/{}", device.getDeviceId(), channelId);  
626 - cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);  
627 - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {  
628 - logger.error("[命令发送失败] 停止点播 停止, 发送BYE: {}", e.getMessage());  
629 - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());  
630 - } 694 + dynamicTask.stop(playBackTimeOutTaskKey);
  695 + // 释放ssrc
  696 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
631 697
632 - dynamicTask.stop(playBackTimeOutTaskKey);  
633 - // 释放ssrc  
634 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
635 - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());  
636 - errorEvent.response(eventResult);  
637 - eventResult.msg = "下级自定义了ssrc,重新设置收流信息失败";  
638 - eventResult.statusCode = 500;  
639 - errorEvent.response(eventResult);  
640 - }  
641 - }); 698 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  699 +
  700 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  701 + "下级自定义了ssrc,重新设置收流信息失败", null);
  702 +
  703 + }else {
  704 + ssrcInfo.setSsrc(ssrcInResponse);
  705 + inviteInfo.setSsrcInfo(ssrcInfo);
  706 + inviteInfo.setStream(ssrcInfo.getStream());
642 } 707 }
  708 + }else {
  709 + logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
643 } 710 }
644 } 711 }
645 - 712 + inviteStreamService.updateInviteInfo(inviteInfo);
646 }, errorEvent); 713 }, errorEvent);
647 } catch (InvalidArgumentException | SipException | ParseException e) { 714 } catch (InvalidArgumentException | SipException | ParseException e) {
648 logger.error("[命令发送失败] 回放: {}", e.getMessage()); 715 logger.error("[命令发送失败] 回放: {}", e.getMessage());
@@ -658,42 +725,50 @@ public class PlayServiceImpl implements IPlayService { @@ -658,42 +725,50 @@ public class PlayServiceImpl implements IPlayService {
658 725
659 726
660 @Override 727 @Override
661 - public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback) { 728 + public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) {
662 Device device = storager.queryVideoDevice(deviceId); 729 Device device = storager.queryVideoDevice(deviceId);
663 if (device == null) { 730 if (device == null) {
664 return; 731 return;
665 } 732 }
666 MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device); 733 MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device);
667 if (newMediaServerItem == null) { 734 if (newMediaServerItem == null) {
668 - PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();  
669 - downloadResult.setCode(ErrorCode.ERROR100.getCode());  
670 - downloadResult.setMsg("未找到assist服务");  
671 - playBackCallback.call(downloadResult); 735 + callback.run(InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getCode(),
  736 + InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getMsg(),
  737 + null);
672 return; 738 return;
673 } 739 }
674 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); 740 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
675 - download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, infoCallBack, playBackCallback); 741 + download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, callback);
676 } 742 }
677 743
678 744
679 @Override 745 @Override
680 - public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) { 746 + public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) {
681 if (mediaServerItem == null || ssrcInfo == null) { 747 if (mediaServerItem == null || ssrcInfo == null) {
  748 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  749 + InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
  750 + null);
682 return; 751 return;
683 } 752 }
684 -  
685 Device device = storager.queryVideoDevice(deviceId); 753 Device device = storager.queryVideoDevice(deviceId);
686 if (device == null) { 754 if (device == null) {
687 - throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "不存在"); 755 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  756 + "设备:" + deviceId + "不存在",
  757 + null);
  758 + return;
688 } 759 }
689 - PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();  
690 - logger.info("[录像下载] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); 760 + logger.info("[录像下载] deviceId: {}, channelId: {}, 下载速度:{}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, downloadSpeed, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  761 + // 初始化redis中的invite消息状态
  762 + InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  763 + mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD,
  764 + InviteSessionStatus.ready);
  765 + inviteStreamService.updateInviteInfo(inviteInfo);
691 String downLoadTimeOutTaskKey = UUID.randomUUID().toString(); 766 String downLoadTimeOutTaskKey = UUID.randomUUID().toString();
692 dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> { 767 dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> {
693 logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId)); 768 logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
694 - downloadResult.setCode(ErrorCode.ERROR100.getCode());  
695 - downloadResult.setMsg("录像下载请求超时");  
696 - hookCallBack.call(downloadResult); 769 + inviteStreamService.removeInviteInfo(inviteInfo);
  770 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(),
  771 + InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null);
697 772
698 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 773 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
699 try { 774 try {
@@ -709,98 +784,128 @@ public class PlayServiceImpl implements IPlayService { @@ -709,98 +784,128 @@ public class PlayServiceImpl implements IPlayService {
709 784
710 SipSubscribe.Event errorEvent = event -> { 785 SipSubscribe.Event errorEvent = event -> {
711 dynamicTask.stop(downLoadTimeOutTaskKey); 786 dynamicTask.stop(downLoadTimeOutTaskKey);
712 - downloadResult.setCode(ErrorCode.ERROR100.getCode());  
713 - downloadResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg));  
714 - downloadResult.setEvent(event);  
715 - hookCallBack.call(downloadResult); 787 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(),
  788 + String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg), null);
716 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 789 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  790 + inviteStreamService.removeInviteInfo(inviteInfo);
717 }; 791 };
718 - InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {  
719 - logger.info("[录像下载]收到订阅消息: " + inviteStreamInfo.getCallId()); 792 + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> {
  793 + logger.info("[录像下载]收到订阅消息: " + jsonObject);
720 dynamicTask.stop(downLoadTimeOutTaskKey); 794 dynamicTask.stop(downLoadTimeOutTaskKey);
721 - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);  
722 - streamInfo.setStartTime(startTime);  
723 - streamInfo.setEndTime(endTime);  
724 - redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());  
725 - downloadResult.setCode(ErrorCode.SUCCESS.getCode());  
726 - downloadResult.setMsg(ErrorCode.SUCCESS.getMsg());  
727 - downloadResult.setData(streamInfo);  
728 - downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());  
729 - downloadResult.setResponse(inviteStreamInfo.getResponse());  
730 - hookCallBack.call(downloadResult); 795 + StreamInfo streamInfo = onPublishHandlerForDownload(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime);
  796 + if (streamInfo == null) {
  797 + logger.warn("[录像下载] 获取流地址信息失败");
  798 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  799 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  800 + return;
  801 + }
  802 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  803 + logger.info("[录像下载] 调用成功 deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}", device.getDeviceId(), channelId, startTime, endTime);
731 }; 804 };
732 try { 805 try {
733 - cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack,  
734 - hookEvent, errorEvent, eventResult ->  
735 - {  
736 - if (eventResult.type == SipSubscribe.EventResultType.response) {  
737 - ResponseEvent responseEvent = (ResponseEvent) eventResult.event;  
738 - String contentString = new String(responseEvent.getResponse().getRawContent());  
739 - // 获取ssrc  
740 - int ssrcIndex = contentString.indexOf("y=");  
741 - // 检查是否有y字段  
742 - if (ssrcIndex >= 0) {  
743 - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容  
744 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
745 - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理  
746 - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {  
747 - return;  
748 - }  
749 - logger.info("[录像下载] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);  
750 - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {  
751 - logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);  
752 -  
753 - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {  
754 - // ssrc 不可用 806 + cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed,
  807 + hookEvent, errorEvent, eventResult ->{
  808 + inviteInfo.setStatus(InviteSessionStatus.ok);
  809 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
  810 + String contentString = new String(responseEvent.getResponse().getRawContent());
  811 + // 获取ssrc
  812 + int ssrcIndex = contentString.indexOf("y=");
  813 + // 检查是否有y字段
  814 + if (ssrcIndex >= 0) {
  815 + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  816 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  817 + // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  818 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  819 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  820 + String substring = contentString.substring(0, contentString.indexOf("y="));
  821 + try {
  822 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  823 + int port = -1;
  824 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  825 + for (Object description : mediaDescriptions) {
  826 + MediaDescription mediaDescription = (MediaDescription) description;
  827 + Media media = mediaDescription.getMedia();
  828 +
  829 + Vector mediaFormats = media.getMediaFormats(false);
  830 + if (mediaFormats.contains("96")) {
  831 + port = media.getMediaPort();
  832 + break;
  833 + }
  834 + }
  835 + logger.info("[录像下载-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  836 + JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
  837 + logger.info("[录像下载-TCP主动连接对方] 结果: {}", jsonObject);
  838 + } catch (SdpException e) {
  839 + logger.error("[录像下载-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
  840 + dynamicTask.stop(downLoadTimeOutTaskKey);
  841 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
755 // 释放ssrc 842 // 释放ssrc
756 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 843 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  844 +
757 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 845 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
758 - eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用";  
759 - eventResult.statusCode = 400;  
760 - errorEvent.response(eventResult);  
761 - return; 846 +
  847 + callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  848 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  849 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  850 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  851 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
762 } 852 }
  853 + }
  854 + return;
  855 + }
  856 + logger.info("[录像下载] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  857 + if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
  858 + logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  859 +
  860 + if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
  861 + // ssrc 不可用
  862 + // 释放ssrc
  863 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  864 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  865 + callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  866 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  867 + return;
  868 + }
  869 +
  870 + // 单端口模式streamId也有变化,需要重新设置监听
  871 + if (!mediaServerItem.isRtpEnable()) {
  872 + // 添加订阅
  873 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  874 + subscribe.removeSubscribe(hookSubscribe);
  875 + hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
  876 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
  877 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  878 + dynamicTask.stop(downLoadTimeOutTaskKey);
  879 + hookEvent.response(mediaServerItemInUse, response);
  880 + });
  881 + }
763 882
764 - // 单端口模式streamId也有变化,需要重新设置监听  
765 - if (!mediaServerItem.isRtpEnable()) {  
766 - // 添加订阅  
767 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
768 - subscribe.removeSubscribe(hookSubscribe);  
769 - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());  
770 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {  
771 - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());  
772 - dynamicTask.stop(downLoadTimeOutTaskKey);  
773 - // hook响应  
774 - onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, hookCallBack);  
775 - hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));  
776 - }); 883 + // 更新ssrc
  884 + Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
  885 + if (!result) {
  886 + try {
  887 + logger.warn("[录像下载] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);
  888 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  889 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  890 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
777 } 891 }
778 892
779 - // 关闭rtp server  
780 - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{  
781 - if (result) {  
782 - // 重新开启ssrc server  
783 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), true, device.getStreamModeForParam());  
784 - }else {  
785 - try {  
786 - logger.warn("[录像下载] 停止{}/{}", device.getDeviceId(), channelId);  
787 - cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);  
788 - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {  
789 - logger.error("[命令发送失败] 录像下载停止, 发送BYE: {}", e.getMessage());  
790 - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());  
791 - } 893 + dynamicTask.stop(downLoadTimeOutTaskKey);
  894 + // 释放ssrc
  895 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
792 896
793 - dynamicTask.stop(downLoadTimeOutTaskKey);  
794 - // 释放ssrc  
795 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 897 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
796 898
797 - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());  
798 - eventResult.msg = "下级自定义了ssrc,重新设置收流信息失败";  
799 - eventResult.statusCode = 500;  
800 - errorEvent.response(eventResult);  
801 - }  
802 - }); 899 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  900 + "下级自定义了ssrc,重新设置收流信息失败", null);
  901 +
  902 + }else {
  903 + ssrcInfo.setSsrc(ssrcInResponse);
  904 + inviteInfo.setSsrcInfo(ssrcInfo);
  905 + inviteInfo.setStream(ssrcInfo.getStream());
803 } 906 }
  907 + }else {
  908 + logger.info("[录像下载] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
804 } 909 }
805 } 910 }
806 }); 911 });
@@ -817,21 +922,22 @@ public class PlayServiceImpl implements IPlayService { @@ -817,21 +922,22 @@ public class PlayServiceImpl implements IPlayService {
817 922
818 @Override 923 @Override
819 public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) { 924 public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) {
820 - StreamInfo streamInfo = redisCatchStorage.queryDownload(deviceId, channelId, stream, null);  
821 - if (streamInfo != null) {  
822 - if (streamInfo.getProgress() == 1) {  
823 - return streamInfo; 925 + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream);
  926 +
  927 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  928 + if (inviteInfo.getStreamInfo().getProgress() == 1) {
  929 + return inviteInfo.getStreamInfo();
824 } 930 }
825 931
826 // 获取当前已下载时长 932 // 获取当前已下载时长
827 - String mediaServerId = streamInfo.getMediaServerId(); 933 + String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId();
828 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); 934 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
829 if (mediaServerItem == null) { 935 if (mediaServerItem == null) {
830 logger.warn("查询录像信息时发现节点已离线"); 936 logger.warn("查询录像信息时发现节点已离线");
831 return null; 937 return null;
832 } 938 }
833 if (mediaServerItem.getRecordAssistPort() > 0) { 939 if (mediaServerItem.getRecordAssistPort() > 0) {
834 - JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, streamInfo.getApp(), streamInfo.getStream(), null); 940 + JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream(), null);
835 if (jsonObject == null) { 941 if (jsonObject == null) {
836 throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接Assist服务失败"); 942 throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接Assist服务失败");
837 } 943 }
@@ -839,10 +945,10 @@ public class PlayServiceImpl implements IPlayService { @@ -839,10 +945,10 @@ public class PlayServiceImpl implements IPlayService {
839 long duration = jsonObject.getLong("data"); 945 long duration = jsonObject.getLong("data");
840 946
841 if (duration == 0) { 947 if (duration == 0) {
842 - streamInfo.setProgress(0); 948 + inviteInfo.getStreamInfo().setProgress(0);
843 } else { 949 } else {
844 - String startTime = streamInfo.getStartTime();  
845 - String endTime = streamInfo.getEndTime(); 950 + String startTime = inviteInfo.getStreamInfo().getStartTime();
  951 + String endTime = inviteInfo.getStreamInfo().getEndTime();
846 long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); 952 long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
847 long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); 953 long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
848 954
@@ -850,29 +956,31 @@ public class PlayServiceImpl implements IPlayService { @@ -850,29 +956,31 @@ public class PlayServiceImpl implements IPlayService {
850 BigDecimal totalCount = new BigDecimal(end - start); 956 BigDecimal totalCount = new BigDecimal(end - start);
851 BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP); 957 BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP);
852 double process = divide.doubleValue(); 958 double process = divide.doubleValue();
853 - streamInfo.setProgress(process); 959 + inviteInfo.getStreamInfo().setProgress(process);
854 } 960 }
  961 + inviteStreamService.updateInviteInfo(inviteInfo);
855 } 962 }
856 } 963 }
  964 + return inviteInfo.getStreamInfo();
857 } 965 }
858 - return streamInfo; 966 + return null;
859 } 967 }
860 968
861 - @Override  
862 - public void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String uuid) {  
863 - RequestMessage msg = new RequestMessage();  
864 - msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId);  
865 - msg.setId(uuid);  
866 - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); 969 + private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, JSONObject response, String deviceId, String channelId, String startTime, String endTime) {
  970 + StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, response, deviceId, channelId);
867 if (streamInfo != null) { 971 if (streamInfo != null) {
868 - redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());  
869 - msg.setData(JSON.toJSONString(streamInfo));  
870 - resultHolder.invokeResult(msg);  
871 - } else {  
872 - logger.warn("设备预览API调用失败!");  
873 - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "设备预览API调用失败!"));  
874 - resultHolder.invokeResult(msg); 972 + streamInfo.setProgress(0);
  973 + streamInfo.setStartTime(startTime);
  974 + streamInfo.setEndTime(endTime);
  975 + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, streamInfo.getStream());
  976 + if (inviteInfo != null) {
  977 + logger.info("[录像下载] 更新invite消息中的stream信息");
  978 + inviteInfo.setStatus(InviteSessionStatus.ok);
  979 + inviteInfo.setStreamInfo(streamInfo);
  980 + inviteStreamService.updateInviteInfo(inviteInfo);
  981 + }
875 } 982 }
  983 + return streamInfo;
876 } 984 }
877 985
878 986
@@ -976,15 +1084,14 @@ public class PlayServiceImpl implements IPlayService { @@ -976,15 +1084,14 @@ public class PlayServiceImpl implements IPlayService {
976 1084
977 @Override 1085 @Override
978 public void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException { 1086 public void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException {
979 - String key = redisCatchStorage.queryPlaybackForKey(null, null, streamId, null);  
980 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
981 - if (null == streamInfo) { 1087 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  1088 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
982 logger.warn("streamId不存在!"); 1089 logger.warn("streamId不存在!");
983 throw new ServiceException("streamId不存在"); 1090 throw new ServiceException("streamId不存在");
984 } 1091 }
985 - streamInfo.setPause(true);  
986 - redisTemplate.opsForValue().set(key, streamInfo);  
987 - MediaServerItem mediaServerItem = mediaServerService.getOne(streamInfo.getMediaServerId()); 1092 + inviteInfo.getStreamInfo().setPause(true);
  1093 + inviteStreamService.updateInviteInfo(inviteInfo);
  1094 + MediaServerItem mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
988 if (null == mediaServerItem) { 1095 if (null == mediaServerItem) {
989 logger.warn("mediaServer 不存在!"); 1096 logger.warn("mediaServer 不存在!");
990 throw new ServiceException("mediaServer不存在"); 1097 throw new ServiceException("mediaServer不存在");
@@ -994,21 +1101,20 @@ public class PlayServiceImpl implements IPlayService { @@ -994,21 +1101,20 @@ public class PlayServiceImpl implements IPlayService {
994 if (jsonObject == null || jsonObject.getInteger("code") != 0) { 1101 if (jsonObject == null || jsonObject.getInteger("code") != 0) {
995 throw new ServiceException("暂停RTP接收失败"); 1102 throw new ServiceException("暂停RTP接收失败");
996 } 1103 }
997 - Device device = storager.queryVideoDevice(streamInfo.getDeviceID());  
998 - cmder.playPauseCmd(device, streamInfo); 1104 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
  1105 + cmder.playPauseCmd(device, inviteInfo.getStreamInfo());
999 } 1106 }
1000 1107
1001 @Override 1108 @Override
1002 public void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException { 1109 public void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException {
1003 - String key = redisCatchStorage.queryPlaybackForKey(null, null, streamId, null);  
1004 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
1005 - if (null == streamInfo) { 1110 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  1111 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
1006 logger.warn("streamId不存在!"); 1112 logger.warn("streamId不存在!");
1007 throw new ServiceException("streamId不存在"); 1113 throw new ServiceException("streamId不存在");
1008 } 1114 }
1009 - streamInfo.setPause(false);  
1010 - redisTemplate.opsForValue().set(key, streamInfo);  
1011 - MediaServerItem mediaServerItem = mediaServerService.getOne(streamInfo.getMediaServerId()); 1115 + inviteInfo.getStreamInfo().setPause(false);
  1116 + inviteStreamService.updateInviteInfo(inviteInfo);
  1117 + MediaServerItem mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
1012 if (null == mediaServerItem) { 1118 if (null == mediaServerItem) {
1013 logger.warn("mediaServer 不存在!"); 1119 logger.warn("mediaServer 不存在!");
1014 throw new ServiceException("mediaServer不存在"); 1120 throw new ServiceException("mediaServer不存在");
@@ -1018,7 +1124,7 @@ public class PlayServiceImpl implements IPlayService { @@ -1018,7 +1124,7 @@ public class PlayServiceImpl implements IPlayService {
1018 if (jsonObject == null || jsonObject.getInteger("code") != 0) { 1124 if (jsonObject == null || jsonObject.getInteger("code") != 0) {
1019 throw new ServiceException("继续RTP接收失败"); 1125 throw new ServiceException("继续RTP接收失败");
1020 } 1126 }
1021 - Device device = storager.queryVideoDevice(streamInfo.getDeviceID());  
1022 - cmder.playResumeCmd(device, streamInfo); 1127 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
  1128 + cmder.playResumeCmd(device, inviteInfo.getStreamInfo());
1023 } 1129 }
1024 } 1130 }
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
@@ -264,8 +264,8 @@ public class RedisGbPlayMsgListener implements MessageListener { @@ -264,8 +264,8 @@ public class RedisGbPlayMsgListener implements MessageListener {
264 return; 264 return;
265 } 265 }
266 // 确定流是否在线 266 // 确定流是否在线
267 - boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, content.getApp(), content.getStream());  
268 - if (streamReady) { 267 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, content.getApp(), content.getStream());
  268 + if (streamReady != null && streamReady) {
269 logger.info("[回复推流信息] {}/{}", content.getApp(), content.getStream()); 269 logger.info("[回复推流信息] {}/{}", content.getApp(), content.getStream());
270 responseSendItem(mediaServerItem, content, toId, serial); 270 responseSendItem(mediaServerItem, content, toId, serial);
271 }else { 271 }else {
@@ -301,9 +301,6 @@ public class RedisGbPlayMsgListener implements MessageListener { @@ -301,9 +301,6 @@ public class RedisGbPlayMsgListener implements MessageListener {
301 String key = VideoManagerConstants.VM_MSG_STREAM_PUSH_REQUESTED; 301 String key = VideoManagerConstants.VM_MSG_STREAM_PUSH_REQUESTED;
302 logger.info("[redis发送通知] 推流被请求 {}: {}/{}", key, messageForPushChannel.getApp(), messageForPushChannel.getStream()); 302 logger.info("[redis发送通知] 推流被请求 {}: {}/{}", key, messageForPushChannel.getApp(), messageForPushChannel.getStream());
303 redisTemplate.convertAndSend(key, JSON.toJSON(messageForPushChannel)); 303 redisTemplate.convertAndSend(key, JSON.toJSON(messageForPushChannel));
304 -  
305 -// redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);  
306 -  
307 } 304 }
308 } 305 }
309 306
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
1 package com.genersoft.iot.vmp.storager; 1 package com.genersoft.iot.vmp.storager;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
4 -import com.genersoft.iot.vmp.common.StreamInfo;  
5 import com.genersoft.iot.vmp.common.SystemAllInfo; 4 import com.genersoft.iot.vmp.common.SystemAllInfo;
6 -import com.genersoft.iot.vmp.gb28181.bean.*;  
7 -import com.genersoft.iot.vmp.media.zlm.dto.*; 5 +import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage;
  6 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  7 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  8 +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  10 +import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
8 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; 11 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
9 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; 12 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
10 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 13 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
11 -import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;  
12 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; 14 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
13 15
14 import java.util.List; 16 import java.util.List;
@@ -23,42 +25,6 @@ public interface IRedisCatchStorage { @@ -23,42 +25,6 @@ public interface IRedisCatchStorage {
23 */ 25 */
24 Long getCSEQ(); 26 Long getCSEQ();
25 27
26 - /**  
27 - * 开始播放时将流存入  
28 - *  
29 - * @param stream 流信息  
30 - * @return  
31 - */  
32 - boolean startPlay(StreamInfo stream);  
33 -  
34 -  
35 - /**  
36 - * 停止播放时删除  
37 - *  
38 - * @return  
39 - */  
40 - boolean stopPlay(StreamInfo streamInfo);  
41 -  
42 - /**  
43 - * 查询播放列表  
44 - * @return  
45 - */  
46 - StreamInfo queryPlay(StreamInfo streamInfo);  
47 -  
48 - StreamInfo queryPlayByStreamId(String steamId);  
49 -  
50 - StreamInfo queryPlayByDevice(String deviceId, String channelId);  
51 -  
52 - Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);  
53 -  
54 - boolean startPlayback(StreamInfo stream, String callId);  
55 -  
56 - boolean stopPlayback(String deviceId, String channelId, String stream, String callId);  
57 -  
58 - StreamInfo queryPlayback(String deviceId, String channelID, String stream, String callId);  
59 -  
60 - String queryPlaybackForKey(String deviceId, String channelId, String stream, String callId);  
61 -  
62 void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch); 28 void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch);
63 29
64 ParentPlatformCatch queryPlatformCatchInfo(String platformGbId); 30 ParentPlatformCatch queryPlatformCatchInfo(String platformGbId);
@@ -75,8 +41,6 @@ public interface IRedisCatchStorage { @@ -75,8 +41,6 @@ public interface IRedisCatchStorage {
75 41
76 void delPlatformRegisterInfo(String callId); 42 void delPlatformRegisterInfo(String callId);
77 43
78 - void cleanPlatformRegisterInfos();  
79 -  
80 void updateSendRTPSever(SendRtpItem sendRtpItem); 44 void updateSendRTPSever(SendRtpItem sendRtpItem);
81 45
82 /** 46 /**
@@ -103,12 +67,6 @@ public interface IRedisCatchStorage { @@ -103,12 +67,6 @@ public interface IRedisCatchStorage {
103 boolean isChannelSendingRTP(String channelId); 67 boolean isChannelSendingRTP(String channelId);
104 68
105 /** 69 /**
106 - * 清空某个设备的所有缓存  
107 - * @param deviceId 设备ID  
108 - */  
109 - void clearCatchByDeviceId(String deviceId);  
110 -  
111 - /**  
112 * 在redis添加wvp的信息 70 * 在redis添加wvp的信息
113 */ 71 */
114 void updateWVPInfo(JSONObject jsonObject, int time); 72 void updateWVPInfo(JSONObject jsonObject, int time);
@@ -148,23 +106,6 @@ public interface IRedisCatchStorage { @@ -148,23 +106,6 @@ public interface IRedisCatchStorage {
148 */ 106 */
149 void removeStream(String mediaServerId, String type); 107 void removeStream(String mediaServerId, String type);
150 108
151 - /**  
152 - * 开始下载录像时存入  
153 - * @param streamInfo  
154 - */  
155 - boolean startDownload(StreamInfo streamInfo, String callId);  
156 -  
157 - StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId);  
158 -  
159 - boolean stopDownload(String deviceId, String channelId, String stream, String callId);  
160 -  
161 - /**  
162 - * 查找第三方系统留下的国标预设值  
163 - * @param queryKey  
164 - * @return  
165 - */  
166 - ThirdPartyGB queryMemberNoGBId(String queryKey);  
167 -  
168 List<OnStreamChangedHookParam> getStreams(String mediaServerId, String pull); 109 List<OnStreamChangedHookParam> getStreams(String mediaServerId, String pull);
169 110
170 /** 111 /**
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -2,17 +2,18 @@ package com.genersoft.iot.vmp.storager.impl; @@ -2,17 +2,18 @@ package com.genersoft.iot.vmp.storager.impl;
2 2
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.alibaba.fastjson2.JSONObject; 4 import com.alibaba.fastjson2.JSONObject;
5 -import com.genersoft.iot.vmp.common.StreamInfo;  
6 import com.genersoft.iot.vmp.common.SystemAllInfo; 5 import com.genersoft.iot.vmp.common.SystemAllInfo;
7 import com.genersoft.iot.vmp.common.VideoManagerConstants; 6 import com.genersoft.iot.vmp.common.VideoManagerConstants;
8 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
9 -import com.genersoft.iot.vmp.gb28181.bean.*;  
10 -import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; 8 +import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage;
  9 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  10 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  11 +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 12 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; 13 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
  14 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
13 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; 15 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
14 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 16 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
15 -import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;  
16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 17 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
17 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; 18 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
18 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; 19 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
@@ -92,241 +93,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -92,241 +93,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
92 } 93 }
93 } 94 }
94 95
95 - /**  
96 - * 开始播放时将流存入redis  
97 - */  
98 - @Override  
99 - public boolean startPlay(StreamInfo stream) {  
100 -  
101 - redisTemplate.opsForValue().set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, userSetting.getServerId(),  
102 - stream.getMediaServerId(), stream.getStream(), stream.getDeviceID(), stream.getChannelId()),  
103 - stream);  
104 - return true;  
105 - }  
106 -  
107 - /**  
108 - * 停止播放时从redis删除  
109 - */  
110 - @Override  
111 - public boolean stopPlay(StreamInfo streamInfo) {  
112 - if (streamInfo == null) {  
113 - return false;  
114 - }  
115 - Boolean result = redisTemplate.delete(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,  
116 - userSetting.getServerId(),  
117 - streamInfo.getMediaServerId(),  
118 - streamInfo.getStream(),  
119 - streamInfo.getDeviceID(),  
120 - streamInfo.getChannelId()));  
121 - return result != null && result;  
122 - }  
123 -  
124 - /**  
125 - * 查询播放列表  
126 - */  
127 - @Override  
128 - public StreamInfo queryPlay(StreamInfo streamInfo) {  
129 - return (StreamInfo)redisTemplate.opsForValue().get(String.format("%S_%s_%s_%s_%s_%s",  
130 - VideoManagerConstants.PLAYER_PREFIX,  
131 - userSetting.getServerId(),  
132 - streamInfo.getMediaServerId(),  
133 - streamInfo.getStream(),  
134 - streamInfo.getDeviceID(),  
135 - streamInfo.getChannelId()));  
136 - }  
137 - @Override  
138 - public StreamInfo queryPlayByStreamId(String streamId) {  
139 - List<Object> playLeys = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_%s_*", VideoManagerConstants.PLAYER_PREFIX, userSetting.getServerId(), streamId));  
140 - if (playLeys.size() == 0) {  
141 - return null;  
142 - }  
143 - return (StreamInfo)redisTemplate.opsForValue().get(playLeys.get(0).toString());  
144 - }  
145 -  
146 - @Override  
147 - public StreamInfo queryPlayByDevice(String deviceId, String channelId) {  
148 - List<Object> playLeys = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,  
149 - userSetting.getServerId(),  
150 - deviceId,  
151 - channelId));  
152 - if (playLeys.size() == 0) {  
153 - return null;  
154 - }  
155 - return (StreamInfo)redisTemplate.opsForValue().get(playLeys.get(0).toString());  
156 - }  
157 -  
158 - @Override  
159 - public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {  
160 - Map<String, StreamInfo> streamInfos = new HashMap<>();  
161 - List<Object> players = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_*_%s_*", VideoManagerConstants.PLAYER_PREFIX, userSetting.getServerId(),deviceId));  
162 - if (players.size() == 0) {  
163 - return streamInfos;  
164 - }  
165 - for (Object player : players) {  
166 - String key = (String) player;  
167 - StreamInfo streamInfo = JsonUtil.redisJsonToObject(redisTemplate, key, StreamInfo.class);  
168 - if (Objects.isNull(streamInfo)) {  
169 - continue;  
170 - }  
171 - streamInfos.put(streamInfo.getDeviceID() + "_" + streamInfo.getChannelId(), streamInfo);  
172 - }  
173 - return streamInfos;  
174 - }  
175 -  
176 -  
177 - @Override  
178 - public boolean startPlayback(StreamInfo stream, String callId) {  
179 - redisTemplate.opsForValue().set(String.format("%S_%s_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,  
180 - userSetting.getServerId(), stream.getMediaServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream);  
181 - return true;  
182 - }  
183 -  
184 - @Override  
185 - public boolean startDownload(StreamInfo stream, String callId) {  
186 - String key=String.format("%S_%s_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,  
187 - userSetting.getServerId(), stream.getMediaServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId);  
188 - if (stream.getProgress() == 1) {  
189 - logger.debug("添加下载缓存==已完成下载=》{}",key);  
190 - redisTemplate.opsForValue().set(key, stream);  
191 - }else {  
192 - logger.debug("添加下载缓存==未完成下载=》{}",key);  
193 - Duration duration = Duration.ofSeconds(60*60L);  
194 - redisTemplate.opsForValue().set(key, stream, duration);  
195 - }  
196 - return true;  
197 - }  
198 - @Override  
199 - public boolean stopDownload(String deviceId, String channelId, String stream, String callId) {  
200 - DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);  
201 - if (deviceChannel != null) {  
202 - deviceChannel.setStreamId(null);  
203 - deviceChannel.setDeviceId(deviceId);  
204 - deviceChannelMapper.update(deviceChannel);  
205 - }  
206 - if (deviceId == null) {  
207 - deviceId = "*";  
208 - }  
209 - if (channelId == null) {  
210 - channelId = "*";  
211 - }  
212 - if (stream == null) {  
213 - stream = "*";  
214 - }  
215 - if (callId == null) {  
216 - callId = "*";  
217 - }  
218 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,  
219 - userSetting.getServerId(),  
220 - deviceId,  
221 - channelId,  
222 - stream,  
223 - callId  
224 - );  
225 - List<Object> scan = RedisUtil.scan(redisTemplate, key);  
226 - if (scan.size() > 0) {  
227 - for (Object keyObj : scan) {  
228 - redisTemplate.delete(keyObj);  
229 - }  
230 - }  
231 - return true;  
232 - }  
233 -  
234 - @Override  
235 - public boolean stopPlayback(String deviceId, String channelId, String stream, String callId) {  
236 - DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);  
237 - if (deviceChannel != null) {  
238 - deviceChannel.setStreamId(null);  
239 - deviceChannel.setDeviceId(deviceId);  
240 - deviceChannelMapper.update(deviceChannel);  
241 - }  
242 - if (deviceId == null) {  
243 - deviceId = "*";  
244 - }  
245 - if (channelId == null) {  
246 - channelId = "*";  
247 - }  
248 - if (stream == null) {  
249 - stream = "*";  
250 - }  
251 - if (callId == null) {  
252 - callId = "*";  
253 - }  
254 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,  
255 - userSetting.getServerId(),  
256 - deviceId,  
257 - channelId,  
258 - stream,  
259 - callId  
260 - );  
261 - List<Object> scan = RedisUtil.scan(redisTemplate, key);  
262 - if (scan.size() > 0) {  
263 - for (Object keyObj : scan) {  
264 - redisTemplate.delete(keyObj);  
265 - }  
266 - }  
267 - return true;  
268 - }  
269 -  
270 - @Override  
271 - public StreamInfo queryPlayback(String deviceId, String channelId, String stream, String callId) {  
272 - if (stream == null && callId == null) {  
273 - return null;  
274 - }  
275 - if (deviceId == null) {  
276 - deviceId = "*";  
277 - }  
278 - if (channelId == null) {  
279 - channelId = "*";  
280 - }  
281 - if (stream == null) {  
282 - stream = "*";  
283 - }  
284 - if (callId == null) {  
285 - callId = "*";  
286 - }  
287 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,  
288 - userSetting.getServerId(),  
289 - deviceId,  
290 - channelId,  
291 - stream,  
292 - callId  
293 - );  
294 - List<Object> streamInfoScan = RedisUtil.scan(redisTemplate, key);  
295 - if (streamInfoScan.size() > 0) {  
296 - return (StreamInfo) redisTemplate.opsForValue().get(streamInfoScan.get(0));  
297 - }else {  
298 - return null;  
299 - }  
300 - }  
301 -  
302 - @Override  
303 - public String queryPlaybackForKey(String deviceId, String channelId, String stream, String callId) {  
304 - if (stream == null && callId == null) {  
305 - return null;  
306 - }  
307 - if (deviceId == null) {  
308 - deviceId = "*";  
309 - }  
310 - if (channelId == null) {  
311 - channelId = "*";  
312 - }  
313 - if (stream == null) {  
314 - stream = "*";  
315 - }  
316 - if (callId == null) {  
317 - callId = "*";  
318 - }  
319 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,  
320 - userSetting.getServerId(),  
321 - deviceId,  
322 - channelId,  
323 - stream,  
324 - callId  
325 - );  
326 - List<Object> streamInfoScan = RedisUtil.scan(redisTemplate, key);  
327 - return (String) streamInfoScan.get(0);  
328 - }  
329 -  
330 @Override 96 @Override
331 public void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch) { 97 public void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch) {
332 String key = VideoManagerConstants.PLATFORM_CATCH_PREFIX + userSetting.getServerId() + "_" + parentPlatformCatch.getId(); 98 String key = VideoManagerConstants.PLATFORM_CATCH_PREFIX + userSetting.getServerId() + "_" + parentPlatformCatch.getId();
@@ -373,14 +139,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -373,14 +139,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
373 } 139 }
374 140
375 @Override 141 @Override
376 - public void cleanPlatformRegisterInfos() {  
377 - List regInfos = RedisUtil.scan(redisTemplate, VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetting.getServerId() + "_" + "*");  
378 - for (Object key : regInfos) {  
379 - redisTemplate.delete(key.toString());  
380 - }  
381 - }  
382 -  
383 - @Override  
384 public void updateSendRTPSever(SendRtpItem sendRtpItem) { 142 public void updateSendRTPSever(SendRtpItem sendRtpItem) {
385 143
386 String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + 144 String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX +
@@ -537,36 +295,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -537,36 +295,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
537 } 295 }
538 296
539 @Override 297 @Override
540 - public void clearCatchByDeviceId(String deviceId) {  
541 - List<Object> playLeys = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_%s_*", VideoManagerConstants.PLAYER_PREFIX,  
542 - userSetting.getServerId(),  
543 - deviceId));  
544 - if (playLeys.size() > 0) {  
545 - for (Object key : playLeys) {  
546 - redisTemplate.delete(key.toString());  
547 - }  
548 - }  
549 -  
550 - List<Object> playBackers = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_%s_*_*_*", VideoManagerConstants.PLAY_BLACK_PREFIX,  
551 - userSetting.getServerId(),  
552 - deviceId));  
553 - if (playBackers.size() > 0) {  
554 - for (Object key : playBackers) {  
555 - redisTemplate.delete(key.toString());  
556 - }  
557 - }  
558 -  
559 - List<Object> deviceCache = RedisUtil.scan(redisTemplate, String.format("%S%s_%s", VideoManagerConstants.DEVICE_PREFIX,  
560 - userSetting.getServerId(),  
561 - deviceId));  
562 - if (deviceCache.size() > 0) {  
563 - for (Object key : deviceCache) {  
564 - redisTemplate.delete(key.toString());  
565 - }  
566 - }  
567 - }  
568 -  
569 - @Override  
570 public void updateWVPInfo(JSONObject jsonObject, int time) { 298 public void updateWVPInfo(JSONObject jsonObject, int time) {
571 String key = VideoManagerConstants.WVP_SERVER_PREFIX + userSetting.getServerId(); 299 String key = VideoManagerConstants.WVP_SERVER_PREFIX + userSetting.getServerId();
572 Duration duration = Duration.ofSeconds(time); 300 Duration duration = Duration.ofSeconds(time);
@@ -598,44 +326,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -598,44 +326,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
598 } 326 }
599 327
600 @Override 328 @Override
601 - public StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId) {  
602 - if (stream == null && callId == null) {  
603 - return null;  
604 - }  
605 - if (deviceId == null) {  
606 - deviceId = "*";  
607 - }  
608 - if (channelId == null) {  
609 - channelId = "*";  
610 - }  
611 - if (stream == null) {  
612 - stream = "*";  
613 - }  
614 - if (callId == null) {  
615 - callId = "*";  
616 - }  
617 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,  
618 - userSetting.getServerId(),  
619 - deviceId,  
620 - channelId,  
621 - stream,  
622 - callId  
623 - );  
624 - List<Object> streamInfoScan = RedisUtil.scan(redisTemplate, key);  
625 - if (streamInfoScan.size() > 0) {  
626 - return (StreamInfo) redisTemplate.opsForValue().get(streamInfoScan.get(0));  
627 - }else {  
628 - return null;  
629 - }  
630 - }  
631 -  
632 - @Override  
633 - public ThirdPartyGB queryMemberNoGBId(String queryKey) {  
634 - String key = VideoManagerConstants.WVP_STREAM_GB_ID_PREFIX + queryKey;  
635 - return JsonUtil.redisJsonToObject(redisTemplate, key, ThirdPartyGB.class);  
636 - }  
637 -  
638 - @Override  
639 public void removeStream(String mediaServerId, String type) { 329 public void removeStream(String mediaServerId, String type) {
640 String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetting.getServerId() + "_" + type + "_*_*_" + mediaServerId; 330 String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetting.getServerId() + "_" + type + "_*_*_" + mediaServerId;
641 List<Object> streams = RedisUtil.scan(redisTemplate, key); 331 List<Object> streams = RedisUtil.scan(redisTemplate, key);
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; @@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
15 import com.genersoft.iot.vmp.service.IDeviceChannelService; 15 import com.genersoft.iot.vmp.service.IDeviceChannelService;
16 import com.genersoft.iot.vmp.service.IDeviceService; 16 import com.genersoft.iot.vmp.service.IDeviceService;
  17 +import com.genersoft.iot.vmp.service.IInviteStreamService;
17 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 18 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
18 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 19 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
19 import com.genersoft.iot.vmp.vmanager.bean.BaseTree; 20 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
@@ -62,6 +63,9 @@ public class DeviceQuery { @@ -62,6 +63,9 @@ public class DeviceQuery {
62 63
63 @Autowired 64 @Autowired
64 private IRedisCatchStorage redisCatchStorage; 65 private IRedisCatchStorage redisCatchStorage;
  66 +
  67 + @Autowired
  68 + private IInviteStreamService inviteStreamService;
65 69
66 @Autowired 70 @Autowired
67 private SIPCommander cmder; 71 private SIPCommander cmder;
@@ -184,7 +188,7 @@ public class DeviceQuery { @@ -184,7 +188,7 @@ public class DeviceQuery {
184 // 清除redis记录 188 // 清除redis记录
185 boolean isSuccess = deviceService.delete(deviceId); 189 boolean isSuccess = deviceService.delete(deviceId);
186 if (isSuccess) { 190 if (isSuccess) {
187 - redisCatchStorage.clearCatchByDeviceId(deviceId); 191 + inviteStreamService.clearInviteInfo(deviceId);
188 // 停止此设备的订阅更新 192 // 停止此设备的订阅更新
189 Set<String> allKeys = dynamicTask.getAllKeys(); 193 Set<String> allKeys = dynamicTask.getAllKeys();
190 for (String key : allKeys) { 194 for (String key : allKeys) {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.vmanager.gb28181.play; @@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.vmanager.gb28181.play;
2 2
3 import com.alibaba.fastjson2.JSONArray; 3 import com.alibaba.fastjson2.JSONArray;
4 import com.alibaba.fastjson2.JSONObject; 4 import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.InviteInfo;
  6 +import com.genersoft.iot.vmp.common.InviteSessionStatus;
  7 +import com.genersoft.iot.vmp.common.InviteSessionType;
5 import com.genersoft.iot.vmp.common.StreamInfo; 8 import com.genersoft.iot.vmp.common.StreamInfo;
6 import com.genersoft.iot.vmp.conf.UserSetting; 9 import com.genersoft.iot.vmp.conf.UserSetting;
7 import com.genersoft.iot.vmp.conf.exception.ControllerException; 10 import com.genersoft.iot.vmp.conf.exception.ControllerException;
@@ -14,12 +17,13 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; @@ -14,12 +17,13 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 17 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
15 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; 18 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
16 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 19 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  20 +import com.genersoft.iot.vmp.service.IInviteStreamService;
17 import com.genersoft.iot.vmp.service.IMediaServerService; 21 import com.genersoft.iot.vmp.service.IMediaServerService;
18 import com.genersoft.iot.vmp.service.IMediaService; 22 import com.genersoft.iot.vmp.service.IMediaService;
19 import com.genersoft.iot.vmp.service.IPlayService; 23 import com.genersoft.iot.vmp.service.IPlayService;
  24 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 25 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
21 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 26 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
22 -import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx;  
23 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 27 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
24 import com.genersoft.iot.vmp.vmanager.bean.StreamContent; 28 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
25 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 29 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
@@ -60,6 +64,9 @@ public class PlayController { @@ -60,6 +64,9 @@ public class PlayController {
60 private IRedisCatchStorage redisCatchStorage; 64 private IRedisCatchStorage redisCatchStorage;
61 65
62 @Autowired 66 @Autowired
  67 + private IInviteStreamService inviteStreamService;
  68 +
  69 + @Autowired
63 private ZLMRESTfulUtils zlmresTfulUtils; 70 private ZLMRESTfulUtils zlmresTfulUtils;
64 71
65 @Autowired 72 @Autowired
@@ -88,14 +95,12 @@ public class PlayController { @@ -88,14 +95,12 @@ public class PlayController {
88 Device device = storager.queryVideoDevice(deviceId); 95 Device device = storager.queryVideoDevice(deviceId);
89 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); 96 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
90 97
91 - RequestMessage msg = new RequestMessage(); 98 + RequestMessage requestMessage = new RequestMessage();
92 String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; 99 String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
93 - boolean exist = resultHolder.exist(key, null);  
94 - msg.setKey(key); 100 + requestMessage.setKey(key);
95 String uuid = UUID.randomUUID().toString(); 101 String uuid = UUID.randomUUID().toString();
96 - msg.setId(uuid); 102 + requestMessage.setId(uuid);
97 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); 103 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
98 - DeferredResultEx<WVPResult<StreamContent>> deferredResultEx = new DeferredResultEx<>(result);  
99 104
100 result.onTimeout(()->{ 105 result.onTimeout(()->{
101 logger.info("点播接口等待超时"); 106 logger.info("点播接口等待超时");
@@ -103,32 +108,33 @@ public class PlayController { @@ -103,32 +108,33 @@ public class PlayController {
103 WVPResult<StreamInfo> wvpResult = new WVPResult<>(); 108 WVPResult<StreamInfo> wvpResult = new WVPResult<>();
104 wvpResult.setCode(ErrorCode.ERROR100.getCode()); 109 wvpResult.setCode(ErrorCode.ERROR100.getCode());
105 wvpResult.setMsg("点播超时"); 110 wvpResult.setMsg("点播超时");
106 - msg.setData(wvpResult);  
107 - resultHolder.invokeResult(msg);  
108 - });  
109 - // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误  
110 - deferredResultEx.setFilter(result1 -> {  
111 - WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1;  
112 - WVPResult<StreamContent> resultStream = new WVPResult<>();  
113 - resultStream.setCode(wvpResult1.getCode());  
114 - resultStream.setMsg(wvpResult1.getMsg());  
115 - if (wvpResult1.getCode() == ErrorCode.SUCCESS.getCode()) {  
116 - StreamInfo data = wvpResult1.getData().clone();  
117 - if (userSetting.getUseSourceIpAsStreamIp()) {  
118 - data.channgeStreamIp(request.getLocalName());  
119 - }  
120 - resultStream.setData(new StreamContent(wvpResult1.getData()));  
121 - }  
122 - return resultStream; 111 + requestMessage.setData(wvpResult);
  112 + resultHolder.invokeResult(requestMessage);
123 }); 113 });
124 114
125 -  
126 // 录像查询以channelId作为deviceId查询 115 // 录像查询以channelId作为deviceId查询
127 - resultHolder.put(key, uuid, deferredResultEx); 116 + resultHolder.put(key, uuid, result);
128 117
129 - if (!exist) {  
130 - playService.play(newMediaServerItem, deviceId, channelId, null, null, null);  
131 - } 118 + playService.play(newMediaServerItem, deviceId, channelId, (code, msg, data) -> {
  119 + WVPResult<StreamContent> wvpResult = new WVPResult<>();
  120 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  121 + wvpResult.setCode(ErrorCode.SUCCESS.getCode());
  122 + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
  123 +
  124 + if (data != null) {
  125 + StreamInfo streamInfo = (StreamInfo)data;
  126 + if (userSetting.getUseSourceIpAsStreamIp()) {
  127 + streamInfo.channgeStreamIp(request.getLocalName());
  128 + }
  129 + wvpResult.setData(new StreamContent(streamInfo));
  130 + }
  131 + }else {
  132 + wvpResult.setCode(code);
  133 + wvpResult.setMsg(msg);
  134 + }
  135 + requestMessage.setData(wvpResult);
  136 + resultHolder.invokeResult(requestMessage);
  137 + });
132 return result; 138 return result;
133 } 139 }
134 140
@@ -149,21 +155,22 @@ public class PlayController { @@ -149,21 +155,22 @@ public class PlayController {
149 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备[" + deviceId + "]不存在"); 155 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备[" + deviceId + "]不存在");
150 } 156 }
151 157
152 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);  
153 - if (streamInfo == null) { 158 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  159 + if (inviteInfo == null) {
154 throw new ControllerException(ErrorCode.ERROR100.getCode(), "点播未找到"); 160 throw new ControllerException(ErrorCode.ERROR100.getCode(), "点播未找到");
155 } 161 }
156 -  
157 - try {  
158 - logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);  
159 - cmder.streamByeCmd(device, channelId, streamInfo.getStream(), null, null);  
160 - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {  
161 - logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());  
162 - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); 162 + if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
  163 + try {
  164 + logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
  165 + cmder.streamByeCmd(device, channelId, inviteInfo.getStream(), null, null);
  166 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  167 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
  168 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
  169 + }
163 } 170 }
164 - redisCatchStorage.stopPlay(streamInfo); 171 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
165 172
166 - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 173 + storager.stopPlay(deviceId, channelId);
167 JSONObject json = new JSONObject(); 174 JSONObject json = new JSONObject();
168 json.put("deviceId", deviceId); 175 json.put("deviceId", deviceId);
169 json.put("channelId", channelId); 176 json.put("channelId", channelId);
@@ -178,15 +185,14 @@ public class PlayController { @@ -178,15 +185,14 @@ public class PlayController {
178 @Parameter(name = "streamId", description = "视频流ID", required = true) 185 @Parameter(name = "streamId", description = "视频流ID", required = true)
179 @PostMapping("/convert/{streamId}") 186 @PostMapping("/convert/{streamId}")
180 public JSONObject playConvert(@PathVariable String streamId) { 187 public JSONObject playConvert(@PathVariable String streamId) {
181 - StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);  
182 - if (streamInfo == null) {  
183 - streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
184 - }  
185 - if (streamInfo == null) { 188 +// StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
  189 +
  190 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, streamId);
  191 + if (inviteInfo == null || inviteInfo.getStreamInfo() == null) {
186 logger.warn("视频转码API调用失败!, 视频流已经停止!"); 192 logger.warn("视频转码API调用失败!, 视频流已经停止!");
187 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到视频流信息, 视频流可能已经停止"); 193 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到视频流信息, 视频流可能已经停止");
188 } 194 }
189 - MediaServerItem mediaInfo = mediaServerService.getOne(streamInfo.getMediaServerId()); 195 + MediaServerItem mediaInfo = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
190 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId); 196 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
191 if (!rtpInfo.getBoolean("exist")) { 197 if (!rtpInfo.getBoolean("exist")) {
192 logger.warn("视频转码API调用失败!, 视频流已停止推流!"); 198 logger.warn("视频转码API调用失败!, 视频流已停止推流!");
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
1 package com.genersoft.iot.vmp.vmanager.gb28181.playback; 1 package com.genersoft.iot.vmp.vmanager.gb28181.playback;
2 2
  3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
3 import com.genersoft.iot.vmp.common.StreamInfo; 5 import com.genersoft.iot.vmp.common.StreamInfo;
4 import com.genersoft.iot.vmp.conf.UserSetting; 6 import com.genersoft.iot.vmp.conf.UserSetting;
5 import com.genersoft.iot.vmp.conf.exception.ControllerException; 7 import com.genersoft.iot.vmp.conf.exception.ControllerException;
6 import com.genersoft.iot.vmp.conf.exception.ServiceException; 8 import com.genersoft.iot.vmp.conf.exception.ServiceException;
7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 9 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
  10 +import com.genersoft.iot.vmp.gb28181.bean.Device;
8 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 11 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
9 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 12 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  13 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
10 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 14 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
11 -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 15 +import com.genersoft.iot.vmp.service.IInviteStreamService;
12 import com.genersoft.iot.vmp.service.IPlayService; 16 import com.genersoft.iot.vmp.service.IPlayService;
  17 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
  18 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  19 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
13 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 20 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
14 import com.genersoft.iot.vmp.vmanager.bean.StreamContent; 21 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
15 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 22 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
@@ -20,17 +27,13 @@ import org.slf4j.Logger; @@ -20,17 +27,13 @@ import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory; 27 import org.slf4j.LoggerFactory;
21 import org.springframework.beans.factory.annotation.Autowired; 28 import org.springframework.beans.factory.annotation.Autowired;
22 import org.springframework.util.ObjectUtils; 29 import org.springframework.util.ObjectUtils;
23 -import org.springframework.web.bind.annotation.CrossOrigin;  
24 import org.springframework.web.bind.annotation.GetMapping; 30 import org.springframework.web.bind.annotation.GetMapping;
25 import org.springframework.web.bind.annotation.PathVariable; 31 import org.springframework.web.bind.annotation.PathVariable;
26 import org.springframework.web.bind.annotation.RequestMapping; 32 import org.springframework.web.bind.annotation.RequestMapping;
27 import org.springframework.web.bind.annotation.RestController; 33 import org.springframework.web.bind.annotation.RestController;
28 -  
29 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
30 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;  
31 -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;  
32 import org.springframework.web.context.request.async.DeferredResult; 34 import org.springframework.web.context.request.async.DeferredResult;
33 35
  36 +import javax.servlet.http.HttpServletRequest;
34 import javax.sip.InvalidArgumentException; 37 import javax.sip.InvalidArgumentException;
35 import javax.sip.SipException; 38 import javax.sip.SipException;
36 import java.text.ParseException; 39 import java.text.ParseException;
@@ -60,6 +63,9 @@ public class PlaybackController { @@ -60,6 +63,9 @@ public class PlaybackController {
60 private IRedisCatchStorage redisCatchStorage; 63 private IRedisCatchStorage redisCatchStorage;
61 64
62 @Autowired 65 @Autowired
  66 + private IInviteStreamService inviteStreamService;
  67 +
  68 + @Autowired
63 private IPlayService playService; 69 private IPlayService playService;
64 70
65 @Autowired 71 @Autowired
@@ -74,8 +80,8 @@ public class PlaybackController { @@ -74,8 +80,8 @@ public class PlaybackController {
74 @Parameter(name = "startTime", description = "开始时间", required = true) 80 @Parameter(name = "startTime", description = "开始时间", required = true)
75 @Parameter(name = "endTime", description = "结束时间", required = true) 81 @Parameter(name = "endTime", description = "结束时间", required = true)
76 @GetMapping("/start/{deviceId}/{channelId}") 82 @GetMapping("/start/{deviceId}/{channelId}")
77 - public DeferredResult<WVPResult<StreamContent>> start(@PathVariable String deviceId, @PathVariable String channelId,  
78 - String startTime, String endTime) { 83 + public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
  84 + String startTime, String endTime) {
79 85
80 if (logger.isDebugEnabled()) { 86 if (logger.isDebugEnabled()) {
81 logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); 87 logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
@@ -86,22 +92,31 @@ public class PlaybackController { @@ -86,22 +92,31 @@ public class PlaybackController {
86 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); 92 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
87 resultHolder.put(key, uuid, result); 93 resultHolder.put(key, uuid, result);
88 94
89 - WVPResult<StreamContent> wvpResult = new WVPResult<>();  
90 -  
91 - RequestMessage msg = new RequestMessage();  
92 - msg.setKey(key);  
93 - msg.setId(uuid);  
94 -  
95 - playService.playBack(deviceId, channelId, startTime, endTime, null,  
96 - playBackResult->{  
97 - wvpResult.setCode(playBackResult.getCode());  
98 - wvpResult.setMsg(playBackResult.getMsg());  
99 - if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {  
100 - StreamInfo streamInfo = (StreamInfo)playBackResult.getData();  
101 - wvpResult.setData(new StreamContent(streamInfo)); 95 + RequestMessage requestMessage = new RequestMessage();
  96 + requestMessage.setKey(key);
  97 + requestMessage.setId(uuid);
  98 +
  99 + playService.playBack(deviceId, channelId, startTime, endTime,
  100 + (code, msg, data)->{
  101 +
  102 + WVPResult<StreamContent> wvpResult = new WVPResult<>();
  103 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  104 + wvpResult.setCode(ErrorCode.SUCCESS.getCode());
  105 + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
  106 +
  107 + if (data != null) {
  108 + StreamInfo streamInfo = (StreamInfo)data;
  109 + if (userSetting.getUseSourceIpAsStreamIp()) {
  110 + streamInfo.channgeStreamIp(request.getLocalName());
  111 + }
  112 + wvpResult.setData(new StreamContent(streamInfo));
  113 + }
  114 + }else {
  115 + wvpResult.setCode(code);
  116 + wvpResult.setMsg(msg);
102 } 117 }
103 - msg.setData(wvpResult);  
104 - resultHolder.invokeResult(msg); 118 + requestMessage.setData(wvpResult);
  119 + resultHolder.invokeResult(requestMessage);
105 }); 120 });
106 121
107 return result; 122 return result;
@@ -169,14 +184,15 @@ public class PlaybackController { @@ -169,14 +184,15 @@ public class PlaybackController {
169 @GetMapping("/seek/{streamId}/{seekTime}") 184 @GetMapping("/seek/{streamId}/{seekTime}")
170 public void playSeek(@PathVariable String streamId, @PathVariable long seekTime) { 185 public void playSeek(@PathVariable String streamId, @PathVariable long seekTime) {
171 logger.info("playSeek: "+streamId+", "+seekTime); 186 logger.info("playSeek: "+streamId+", "+seekTime);
172 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
173 - if (null == streamInfo) { 187 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  188 +
  189 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
174 logger.warn("streamId不存在!"); 190 logger.warn("streamId不存在!");
175 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在"); 191 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
176 } 192 }
177 - Device device = storager.queryVideoDevice(streamInfo.getDeviceID()); 193 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
178 try { 194 try {
179 - cmder.playSeekCmd(device, streamInfo, seekTime); 195 + cmder.playSeekCmd(device, inviteInfo.getStreamInfo(), seekTime);
180 } catch (InvalidArgumentException | ParseException | SipException e) { 196 } catch (InvalidArgumentException | ParseException | SipException e) {
181 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage()); 197 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
182 } 198 }
@@ -188,8 +204,9 @@ public class PlaybackController { @@ -188,8 +204,9 @@ public class PlaybackController {
188 @GetMapping("/speed/{streamId}/{speed}") 204 @GetMapping("/speed/{streamId}/{speed}")
189 public void playSpeed(@PathVariable String streamId, @PathVariable Double speed) { 205 public void playSpeed(@PathVariable String streamId, @PathVariable Double speed) {
190 logger.info("playSpeed: "+streamId+", "+speed); 206 logger.info("playSpeed: "+streamId+", "+speed);
191 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
192 - if (null == streamInfo) { 207 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  208 +
  209 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
193 logger.warn("streamId不存在!"); 210 logger.warn("streamId不存在!");
194 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在"); 211 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
195 } 212 }
@@ -197,9 +214,9 @@ public class PlaybackController { @@ -197,9 +214,9 @@ public class PlaybackController {
197 logger.warn("不支持的speed: " + speed); 214 logger.warn("不支持的speed: " + speed);
198 throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持的speed(0.25 0.5 1、2、4)"); 215 throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持的speed(0.25 0.5 1、2、4)");
199 } 216 }
200 - Device device = storager.queryVideoDevice(streamInfo.getDeviceID()); 217 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
201 try { 218 try {
202 - cmder.playSpeedCmd(device, streamInfo, speed); 219 + cmder.playSpeedCmd(device, inviteInfo.getStreamInfo(), speed);
203 } catch (InvalidArgumentException | ParseException | SipException e) { 220 } catch (InvalidArgumentException | ParseException | SipException e) {
204 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage()); 221 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
205 } 222 }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
1 package com.genersoft.iot.vmp.vmanager.gb28181.record; 1 package com.genersoft.iot.vmp.vmanager.gb28181.record;
2 2
3 import com.genersoft.iot.vmp.common.StreamInfo; 3 import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.conf.UserSetting;
4 import com.genersoft.iot.vmp.conf.exception.ControllerException; 5 import com.genersoft.iot.vmp.conf.exception.ControllerException;
5 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 6 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
6 import com.genersoft.iot.vmp.gb28181.bean.Device; 7 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; @@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
11 import com.genersoft.iot.vmp.service.IDeviceService; 12 import com.genersoft.iot.vmp.service.IDeviceService;
12 import com.genersoft.iot.vmp.service.IPlayService; 13 import com.genersoft.iot.vmp.service.IPlayService;
  14 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
13 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 15 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
14 import com.genersoft.iot.vmp.utils.DateUtil; 16 import com.genersoft.iot.vmp.utils.DateUtil;
15 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 17 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
@@ -27,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping; @@ -27,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
27 import org.springframework.web.bind.annotation.RestController; 29 import org.springframework.web.bind.annotation.RestController;
28 import org.springframework.web.context.request.async.DeferredResult; 30 import org.springframework.web.context.request.async.DeferredResult;
29 31
  32 +import javax.servlet.http.HttpServletRequest;
30 import javax.sip.InvalidArgumentException; 33 import javax.sip.InvalidArgumentException;
31 import javax.sip.SipException; 34 import javax.sip.SipException;
32 import java.text.ParseException; 35 import java.text.ParseException;
@@ -55,8 +58,8 @@ public class GBRecordController { @@ -55,8 +58,8 @@ public class GBRecordController {
55 @Autowired 58 @Autowired
56 private IDeviceService deviceService; 59 private IDeviceService deviceService;
57 60
58 -  
59 - 61 + @Autowired
  62 + private UserSetting userSetting;
60 63
61 @Operation(summary = "录像查询") 64 @Operation(summary = "录像查询")
62 @Parameter(name = "deviceId", description = "设备国标编号", required = true) 65 @Parameter(name = "deviceId", description = "设备国标编号", required = true)
@@ -119,8 +122,8 @@ public class GBRecordController { @@ -119,8 +122,8 @@ public class GBRecordController {
119 @Parameter(name = "endTime", description = "结束时间", required = true) 122 @Parameter(name = "endTime", description = "结束时间", required = true)
120 @Parameter(name = "downloadSpeed", description = "下载倍速", required = true) 123 @Parameter(name = "downloadSpeed", description = "下载倍速", required = true)
121 @GetMapping("/download/start/{deviceId}/{channelId}") 124 @GetMapping("/download/start/{deviceId}/{channelId}")
122 - public DeferredResult<WVPResult<StreamContent>> download(@PathVariable String deviceId, @PathVariable String channelId,  
123 - String startTime, String endTime, String downloadSpeed) { 125 + public DeferredResult<WVPResult<StreamContent>> download(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
  126 + String startTime, String endTime, String downloadSpeed) {
124 127
125 if (logger.isDebugEnabled()) { 128 if (logger.isDebugEnabled()) {
126 logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed)); 129 logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed));
@@ -130,22 +133,32 @@ public class GBRecordController { @@ -130,22 +133,32 @@ public class GBRecordController {
130 String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId; 133 String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
131 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(30000L); 134 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(30000L);
132 resultHolder.put(key, uuid, result); 135 resultHolder.put(key, uuid, result);
133 - RequestMessage msg = new RequestMessage();  
134 - msg.setId(uuid);  
135 - msg.setKey(key);  
136 -  
137 - WVPResult<StreamContent> wvpResult = new WVPResult<>();  
138 -  
139 - playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, playBackResult->{  
140 -  
141 - wvpResult.setCode(playBackResult.getCode());  
142 - wvpResult.setMsg(playBackResult.getMsg());  
143 - if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {  
144 - StreamInfo streamInfo = (StreamInfo)playBackResult.getData();  
145 - wvpResult.setData(new StreamContent(streamInfo)); 136 + RequestMessage requestMessage = new RequestMessage();
  137 + requestMessage.setId(uuid);
  138 + requestMessage.setKey(key);
  139 +
  140 +
  141 + playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed),
  142 + (code, msg, data)->{
  143 +
  144 + WVPResult<StreamContent> wvpResult = new WVPResult<>();
  145 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  146 + wvpResult.setCode(ErrorCode.SUCCESS.getCode());
  147 + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
  148 +
  149 + if (data != null) {
  150 + StreamInfo streamInfo = (StreamInfo)data;
  151 + if (userSetting.getUseSourceIpAsStreamIp()) {
  152 + streamInfo.channgeStreamIp(request.getLocalName());
  153 + }
  154 + wvpResult.setData(new StreamContent(streamInfo));
  155 + }
  156 + }else {
  157 + wvpResult.setCode(code);
  158 + wvpResult.setMsg(msg);
146 } 159 }
147 - msg.setData(wvpResult);  
148 - resultHolder.invokeResult(msg); 160 + requestMessage.setData(wvpResult);
  161 + resultHolder.invokeResult(requestMessage);
149 }); 162 });
150 163
151 return result; 164 return result;
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
1 package com.genersoft.iot.vmp.web.gb28181; 1 package com.genersoft.iot.vmp.web.gb28181;
2 2
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.InviteInfo;
  5 +import com.genersoft.iot.vmp.common.InviteSessionType;
5 import com.genersoft.iot.vmp.conf.UserSetting; 6 import com.genersoft.iot.vmp.conf.UserSetting;
6 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
7 import com.genersoft.iot.vmp.gb28181.bean.Device; 8 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -9,13 +10,18 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; @@ -9,13 +10,18 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
9 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
10 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
11 import com.genersoft.iot.vmp.service.IDeviceService; 12 import com.genersoft.iot.vmp.service.IDeviceService;
  13 +import com.genersoft.iot.vmp.service.IInviteStreamService;
12 import com.genersoft.iot.vmp.service.IPlayService; 14 import com.genersoft.iot.vmp.service.IPlayService;
  15 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
13 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
14 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 17 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
15 import org.slf4j.Logger; 18 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory; 19 import org.slf4j.LoggerFactory;
17 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
18 -import org.springframework.web.bind.annotation.*; 21 +import org.springframework.web.bind.annotation.RequestMapping;
  22 +import org.springframework.web.bind.annotation.RequestParam;
  23 +import org.springframework.web.bind.annotation.ResponseBody;
  24 +import org.springframework.web.bind.annotation.RestController;
19 import org.springframework.web.context.request.async.DeferredResult; 25 import org.springframework.web.context.request.async.DeferredResult;
20 26
21 import javax.sip.InvalidArgumentException; 27 import javax.sip.InvalidArgumentException;
@@ -46,6 +52,9 @@ public class ApiStreamController { @@ -46,6 +52,9 @@ public class ApiStreamController {
46 private IRedisCatchStorage redisCatchStorage; 52 private IRedisCatchStorage redisCatchStorage;
47 53
48 @Autowired 54 @Autowired
  55 + private IInviteStreamService inviteStreamService;
  56 +
  57 + @Autowired
49 private IDeviceService deviceService; 58 private IDeviceService deviceService;
50 59
51 @Autowired 60 @Autowired
@@ -111,46 +120,53 @@ public class ApiStreamController { @@ -111,46 +120,53 @@ public class ApiStreamController {
111 return resultDeferredResult; 120 return resultDeferredResult;
112 } 121 }
113 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); 122 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
114 - playService.play(newMediaServerItem, serial, code, (mediaServerItem, response)->{  
115 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(serial, code);  
116 - JSONObject result = new JSONObject();  
117 - result.put("StreamID", streamInfo.getStream());  
118 - result.put("DeviceID", device.getDeviceId());  
119 - result.put("ChannelID", code);  
120 - result.put("ChannelName", deviceChannel.getName());  
121 - result.put("ChannelCustomName", "");  
122 - result.put("FLV", streamInfo.getFlv().getUrl());  
123 - result.put("WS_FLV", streamInfo.getWs_flv().getUrl());  
124 - result.put("RTMP", streamInfo.getRtmp().getUrl());  
125 - result.put("HLS", streamInfo.getHls().getUrl());  
126 - result.put("RTSP", streamInfo.getRtsp().getUrl());  
127 - result.put("WEBRTC", streamInfo.getRtc().getUrl());  
128 - result.put("CDN", "");  
129 - result.put("SnapURL", "");  
130 - result.put("Transport", device.getTransport());  
131 - result.put("StartAt", "");  
132 - result.put("Duration", "");  
133 - result.put("SourceVideoCodecName", "");  
134 - result.put("SourceVideoWidth", "");  
135 - result.put("SourceVideoHeight", "");  
136 - result.put("SourceVideoFrameRate", "");  
137 - result.put("SourceAudioCodecName", "");  
138 - result.put("SourceAudioSampleRate", "");  
139 - result.put("AudioEnable", "");  
140 - result.put("Ondemand", "");  
141 - result.put("InBytes", "");  
142 - result.put("InBitRate", "");  
143 - result.put("OutBytes", "");  
144 - result.put("NumOutputs", "");  
145 - result.put("CascadeSize", "");  
146 - result.put("RelaySize", "");  
147 - result.put("ChannelPTZType", "0");  
148 - resultDeferredResult.setResult(result);  
149 - }, (eventResult) -> {  
150 - JSONObject result = new JSONObject();  
151 - result.put("error", "channel[ " + code + " ] " + eventResult.msg);  
152 - resultDeferredResult.setResult(result);  
153 - }, null); 123 +
  124 +
  125 + playService.play(newMediaServerItem, serial, code, (errorCode, msg, data) -> {
  126 + if (errorCode == InviteErrorCode.SUCCESS.getCode()) {
  127 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, serial, code);
  128 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  129 + JSONObject result = new JSONObject();
  130 + result.put("StreamID", inviteInfo.getStreamInfo().getStream());
  131 + result.put("DeviceID", device.getDeviceId());
  132 + result.put("ChannelID", code);
  133 + result.put("ChannelName", deviceChannel.getName());
  134 + result.put("ChannelCustomName", "");
  135 + result.put("FLV", inviteInfo.getStreamInfo().getFlv().getUrl());
  136 + result.put("WS_FLV", inviteInfo.getStreamInfo().getWs_flv().getUrl());
  137 + result.put("RTMP", inviteInfo.getStreamInfo().getRtmp().getUrl());
  138 + result.put("HLS", inviteInfo.getStreamInfo().getHls().getUrl());
  139 + result.put("RTSP", inviteInfo.getStreamInfo().getRtsp().getUrl());
  140 + result.put("WEBRTC", inviteInfo.getStreamInfo().getRtc().getUrl());
  141 + result.put("CDN", "");
  142 + result.put("SnapURL", "");
  143 + result.put("Transport", device.getTransport());
  144 + result.put("StartAt", "");
  145 + result.put("Duration", "");
  146 + result.put("SourceVideoCodecName", "");
  147 + result.put("SourceVideoWidth", "");
  148 + result.put("SourceVideoHeight", "");
  149 + result.put("SourceVideoFrameRate", "");
  150 + result.put("SourceAudioCodecName", "");
  151 + result.put("SourceAudioSampleRate", "");
  152 + result.put("AudioEnable", "");
  153 + result.put("Ondemand", "");
  154 + result.put("InBytes", "");
  155 + result.put("InBitRate", "");
  156 + result.put("OutBytes", "");
  157 + result.put("NumOutputs", "");
  158 + result.put("CascadeSize", "");
  159 + result.put("RelaySize", "");
  160 + result.put("ChannelPTZType", "0");
  161 + resultDeferredResult.setResult(result);
  162 + }
  163 + }else {
  164 + JSONObject result = new JSONObject();
  165 + result.put("error", "channel[ " + code + " ] " + msg);
  166 + resultDeferredResult.setResult(result);
  167 + }
  168 + });
  169 +
154 return resultDeferredResult; 170 return resultDeferredResult;
155 } 171 }
156 172
@@ -171,8 +187,8 @@ public class ApiStreamController { @@ -171,8 +187,8 @@ public class ApiStreamController {
171 187
172 ){ 188 ){
173 189
174 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(serial, code);  
175 - if (streamInfo == null) { 190 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, serial, code);
  191 + if (inviteInfo == null) {
176 JSONObject result = new JSONObject(); 192 JSONObject result = new JSONObject();
177 result.put("error","未找到流信息"); 193 result.put("error","未找到流信息");
178 return result; 194 return result;
@@ -184,14 +200,14 @@ public class ApiStreamController { @@ -184,14 +200,14 @@ public class ApiStreamController {
184 return result; 200 return result;
185 } 201 }
186 try { 202 try {
187 - cmder.streamByeCmd(device, code, streamInfo.getStream(), null); 203 + cmder.streamByeCmd(device, code, inviteInfo.getStream(), null);
188 } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { 204 } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
189 JSONObject result = new JSONObject(); 205 JSONObject result = new JSONObject();
190 result.put("error","发送BYE失败:" + e.getMessage()); 206 result.put("error","发送BYE失败:" + e.getMessage());
191 return result; 207 return result;
192 } 208 }
193 - redisCatchStorage.stopPlay(streamInfo);  
194 - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 209 + inviteStreamService.removeInviteInfo(inviteInfo);
  210 + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
195 return null; 211 return null;
196 } 212 }
197 213
web_src/src/components/GBRecordDetail.vue
@@ -182,9 +182,11 @@ @@ -182,9 +182,11 @@
182 this.playerStyle["height"] = this.winHeight + "px"; 182 this.playerStyle["height"] = this.winHeight + "px";
183 this.chooseDate = moment().format('YYYY-MM-DD') 183 this.chooseDate = moment().format('YYYY-MM-DD')
184 this.dateChange(); 184 this.dateChange();
  185 + window.addEventListener('beforeunload', this.stopPlayRecord)
185 }, 186 },
186 destroyed() { 187 destroyed() {
187 this.$destroy('recordVideoPlayer'); 188 this.$destroy('recordVideoPlayer');
  189 + window.removeEventListener('beforeunload', this.stopPlayRecord)
188 }, 190 },
189 methods: { 191 methods: {
190 dateChange(){ 192 dateChange(){
@@ -338,14 +340,18 @@ @@ -338,14 +340,18 @@
338 }); 340 });
339 }, 341 },
340 stopPlayRecord: function (callback) { 342 stopPlayRecord: function (callback) {
341 - this.$refs["recordVideoPlayer"].pause();  
342 - this.videoUrl = '';  
343 - this.$axios({  
344 - method: 'get',  
345 - url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId  
346 - }).then(function (res) {  
347 - if (callback) callback()  
348 - }); 343 + console.log("停止录像回放")
  344 + if (this.streamId !== "") {
  345 + this.$refs["recordVideoPlayer"].pause();
  346 + this.videoUrl = '';
  347 + this.$axios({
  348 + method: 'get',
  349 + url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId
  350 + }).then(function (res) {
  351 + if (callback) callback()
  352 + });
  353 + }
  354 +
349 }, 355 },
350 getDataWidth(item){ 356 getDataWidth(item){
351 let timeForFile = this.getTimeForFile(item); 357 let timeForFile = this.getTimeForFile(item);
@@ -423,8 +429,14 @@ @@ -423,8 +429,14 @@
423 return hStr + ":" + mStr + ":" + sStr 429 return hStr + ":" + mStr + ":" + sStr
424 }, 430 },
425 goBack(){ 431 goBack(){
  432 + // 如果正在进行录像回放则,发送停止
  433 + if (this.streamId !== "") {
  434 + this.stopPlayRecord(()=> {
  435 + this.streamId = "";
  436 + })
  437 + }
426 window.history.go(-1); 438 window.history.go(-1);
427 - } 439 + },
428 } 440 }
429 }; 441 };
430 </script> 442 </script>
web_src/src/components/dialog/recordDownload.vue
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 </el-col> 7 </el-col>
8 <el-col :span="6" > 8 <el-col :span="6" >
9 <el-button icon="el-icon-download" v-if="percentage < 100" size="mini" title="点击下载可将以缓存部分下载到本地" @click="download()">停止缓存并下载</el-button> 9 <el-button icon="el-icon-download" v-if="percentage < 100" size="mini" title="点击下载可将以缓存部分下载到本地" @click="download()">停止缓存并下载</el-button>
  10 + <el-button icon="el-icon-download" v-if="downloadFile" size="mini" title="点击下载" @click="downloadFileClientEvent()">点击下载</el-button>
10 </el-col> 11 </el-col>
11 </el-row> 12 </el-row>
12 </el-dialog> 13 </el-dialog>
@@ -21,7 +22,7 @@ import moment from &quot;moment&quot;; @@ -21,7 +22,7 @@ import moment from &quot;moment&quot;;
21 export default { 22 export default {
22 name: 'recordDownload', 23 name: 'recordDownload',
23 created() { 24 created() {
24 - 25 + window.addEventListener('beforeunload', this.stopDownloadRecord)
25 26
26 }, 27 },
27 data() { 28 data() {
@@ -39,7 +40,8 @@ export default { @@ -39,7 +40,8 @@ export default {
39 taskId: null, 40 taskId: null,
40 getProgressRun: false, 41 getProgressRun: false,
41 getProgressForFileRun: false, 42 getProgressForFileRun: false,
42 - timer: null 43 + timer: null,
  44 + downloadFile: null,
43 45
44 }; 46 };
45 }, 47 },
@@ -187,8 +189,9 @@ export default { @@ -187,8 +189,9 @@ export default {
187 this.percentage = parseFloat(res.data.data[0].percentage)*100 189 this.percentage = parseFloat(res.data.data[0].percentage)*100
188 if (res.data.data[0].percentage === '1') { 190 if (res.data.data[0].percentage === '1') {
189 this.getProgressForFileRun = false; 191 this.getProgressForFileRun = false;
190 - window.open(res.data.data[0].downloadFile)  
191 - this.close(); 192 + this.downloadFile = res.data.data[0].downloadFile
  193 + this.title = "文件处理完成,点击按扭下载"
  194 + // window.open(res.data.data[0].downloadFile)
192 }else { 195 }else {
193 if (callback)callback() 196 if (callback)callback()
194 } 197 }
@@ -196,7 +199,13 @@ export default { @@ -196,7 +199,13 @@ export default {
196 }).catch(function (error) { 199 }).catch(function (error) {
197 console.log(error); 200 console.log(error);
198 }); 201 });
199 - } 202 + },
  203 + downloadFileClientEvent: function (){
  204 + window.open(this.downloadFile )
  205 + }
  206 + },
  207 + destroyed() {
  208 + window.removeEventListener('beforeunload', this.stopDownloadRecord)
200 } 209 }
201 }; 210 };
202 </script> 211 </script>