Commit 3cada227435934da8a2db49939695f870b7f477e

Authored by 648540858
2 parents 7d3cbb82 59d8f2f9

Merge branch 'wvp-28181-2.0' into main-dev

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
sql/2.6.9更新.sql 0 → 100644
  1 +alter table wvp_device_channel
  2 + change stream_id stream_id varying(255)
0 3 \ No newline at end of file
... ...
sql/初始化.sql
... ... @@ -79,7 +79,7 @@ create table wvp_device_channel (
79 79 custom_longitude double precision,
80 80 latitude double precision,
81 81 custom_latitude double precision,
82   - stream_id character varying(50),
  82 + stream_id character varying(255),
83 83 device_id character varying(50) not null,
84 84 parental character varying(50),
85 85 has_audio bool default false,
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
... ... @@ -98,6 +98,10 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
98 98 logger.warn("[收到ACK]:未找到来自{},目标为({})的推流信息",fromUserId, toUserId);
99 99 return;
100 100 }
  101 + // tcp主动时,此时是级联下级平台,在回复200ok时,本地已经请求zlm开启监听,跳过下面步骤
  102 + if (sendRtpItem.isTcpActive()) {
  103 + return;
  104 + }
101 105 logger.info("[收到ACK]:rtp/{}开始级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
102 106 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
103 107 // 取消设置的超时任务
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
... ... @@ -50,6 +50,8 @@ import javax.sip.header.CallIdHeader;
50 50 import javax.sip.message.Response;
51 51 import java.text.ParseException;
52 52 import java.time.Instant;
  53 +import java.util.HashMap;
  54 +import java.util.Map;
53 55 import java.util.Random;
54 56 import java.util.Vector;
55 57  
... ... @@ -406,6 +408,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
406 408 content.append("y=" + sendRtpItem.getSsrc() + "\r\n");
407 409 content.append("f=\r\n");
408 410  
  411 +
409 412 try {
410 413 // 超时未收到Ack应该回复bye,当前等待时间为10秒
411 414 dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
... ... @@ -418,8 +421,34 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
418 421 logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
419 422 }
420 423 }, 60 * 1000);
421   -
422   - responseSdpAck(request, content.toString(), platform);
  424 + responseSdpAck(request, content.toString(), platform);
  425 + // tcp主动模式,回复sdp后开启监听
  426 + if (sendRtpItem.isTcpActive()) {
  427 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  428 + Map<String, Object> param = new HashMap<>(12);
  429 + param.put("vhost","__defaultVhost__");
  430 + param.put("app",sendRtpItem.getApp());
  431 + param.put("stream",sendRtpItem.getStreamId());
  432 + param.put("ssrc", sendRtpItem.getSsrc());
  433 + if (!sendRtpItem.isTcpActive()) {
  434 + param.put("dst_url",sendRtpItem.getIp());
  435 + param.put("dst_port", sendRtpItem.getPort());
  436 + }
  437 + String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
  438 + param.put("is_udp", is_Udp);
  439 + param.put("src_port", localPort);
  440 + param.put("pt", sendRtpItem.getPt());
  441 + param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  442 + param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  443 + if (!sendRtpItem.isTcp()) {
  444 + // 开启rtcp保活
  445 + param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
  446 + }
  447 + JSONObject startSendRtpStreamResult = zlmServerFactory.startSendRtpStreamForPassive(mediaInfo, param);
  448 + if (startSendRtpStreamResult != null) {
  449 + startSendRtpStreamHand(evt, sendRtpItem, null, startSendRtpStreamResult, param, callIdHeader);
  450 + }
  451 + }
423 452 } catch (SipException | InvalidArgumentException | ParseException e) {
424 453 logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
425 454 }
... ... @@ -553,6 +582,18 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
553 582 }
554 583 }
555 584  
  585 + private void startSendRtpStreamHand(RequestEvent evt, SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
  586 + JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader) {
  587 + if (jsonObject == null) {
  588 + logger.error("下级TCP被动启动监听失败: 请检查ZLM服务");
  589 + } else if (jsonObject.getInteger("code") == 0) {
  590 + logger.info("调用ZLM-TCP被动推流接口, 结果: {}", jsonObject);
  591 + logger.info("启动监听TCP被动推流成功[ {}/{} ],{}->{}:{}, " ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
  592 + } else {
  593 + logger.error("启动监听TCP被动推流失败: {}, 参数:{}",jsonObject.getString("msg"), JSON.toJSONString(param));
  594 + }
  595 + }
  596 +
556 597 /**
557 598 * 安排推流
558 599 */
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
... ... @@ -59,6 +59,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
59 59 // 未注册的设备不做处理
60 60 return;
61 61 }
  62 + logger.info("[收到心跳], device: {}", device.getDeviceId());
62 63 SIPRequest request = (SIPRequest) evt.getRequest();
63 64 // 回复200 OK
64 65 try {
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -25,8 +25,10 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
25 25 import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
26 26 import com.genersoft.iot.vmp.service.*;
27 27 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
  28 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
28 29 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
29 30 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  31 +import com.genersoft.iot.vmp.utils.DateUtil;
30 32 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
31 33 import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
32 34 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
... ... @@ -641,7 +643,7 @@ public class ZLMHttpHookListener {
641 643  
642 644 if ("rtp".equals(param.getApp())) {
643 645 String[] s = param.getStream().split("_");
644   - if (!mediaInfo.isRtpEnable() || s.length != 2) {
  646 + if (!mediaInfo.isRtpEnable() || (s.length != 2 && s.length != 4)) {
645 647 defaultResult.setResult(HookResult.SUCCESS());
646 648 return defaultResult;
647 649 }
... ... @@ -657,33 +659,79 @@ public class ZLMHttpHookListener {
657 659 defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
658 660 return defaultResult;
659 661 }
660   - logger.info("[ZLM HOOK] 流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
661   -
662   - RequestMessage msg = new RequestMessage();
663   - String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
664   - boolean exist = resultHolder.exist(key, null);
665   - msg.setKey(key);
666   - String uuid = UUID.randomUUID().toString();
667   - msg.setId(uuid);
668   - DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
669   -
670   - result.onTimeout(() -> {
671   - logger.info("[ZLM HOOK] 自动点播, 等待超时");
672   - // 释放rtpserver
673   - msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
674   - resultHolder.invokeResult(msg);
675   - });
676   -
677   - // 录像查询以channelId作为deviceId查询
678   - resultHolder.put(key, uuid, result);
679   -
680   - if (!exist) {
681   - playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> {
682   - msg.setData(new HookResult(code, message));
  662 + if (s.length == 2) {
  663 + logger.info("[ZLM HOOK] 预览流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
  664 +
  665 + RequestMessage msg = new RequestMessage();
  666 + String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
  667 + boolean exist = resultHolder.exist(key, null);
  668 + msg.setKey(key);
  669 + String uuid = UUID.randomUUID().toString();
  670 + msg.setId(uuid);
  671 + DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
  672 +
  673 + result.onTimeout(() -> {
  674 + logger.info("[ZLM HOOK] 预览流自动点播, 等待超时");
  675 + // 释放rtpserver
  676 + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
683 677 resultHolder.invokeResult(msg);
684 678 });
  679 +
  680 + resultHolder.put(key, uuid, result);
  681 +
  682 + if (!exist) {
  683 + playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> {
  684 + msg.setData(new HookResult(code, message));
  685 + resultHolder.invokeResult(msg);
  686 + });
  687 + }
  688 + return result;
  689 + }else if(s.length == 4){
  690 + // 此时为录像回放, 录像回放格式为> 设备ID_通道ID_开始时间_结束时间
  691 + String startTimeStr = s[2];
  692 + String endTimeStr = s[3];
  693 + if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) {
  694 + defaultResult.setResult(HookResult.SUCCESS());
  695 + return defaultResult;
  696 + }
  697 + String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr);
  698 + String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr);
  699 + logger.info("[ZLM HOOK] 回放流未找到, 发起自动点播:{}->{}->{}/{}-{}-{}",
  700 + param.getMediaServerId(), param.getSchema(),
  701 + param.getApp(), param.getStream(),
  702 + startTime, endTime
  703 + );
  704 + RequestMessage msg = new RequestMessage();
  705 + String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
  706 + boolean exist = resultHolder.exist(key, null);
  707 + msg.setKey(key);
  708 + String uuid = UUID.randomUUID().toString();
  709 + msg.setId(uuid);
  710 + DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
  711 +
  712 + result.onTimeout(() -> {
  713 + logger.info("[ZLM HOOK] 回放流自动点播, 等待超时");
  714 + // 释放rtpserver
  715 + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
  716 + resultHolder.invokeResult(msg);
  717 + });
  718 +
  719 + resultHolder.put(key, uuid, result);
  720 +
  721 + if (!exist) {
  722 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null,
  723 + device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
  724 + playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> {
  725 + msg.setData(new HookResult(code, message));
  726 + resultHolder.invokeResult(msg);
  727 + });
  728 + }
  729 + return result;
  730 + }else {
  731 + defaultResult.setResult(HookResult.SUCCESS());
  732 + return defaultResult;
685 733 }
686   - return result;
  734 +
687 735 } else {
688 736 // 拉流代理
689 737 StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
... ...
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
... ... @@ -40,7 +40,6 @@ public interface IPlayService {
40 40  
41 41 void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
42 42 void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
43   -
44 43 void zlmServerOffline(String mediaServerId);
45 44  
46 45 void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
... ... @@ -72,4 +71,6 @@ public interface IPlayService {
72 71 void stopTalk(Device device, String channelId, Boolean streamIsReady);
73 72  
74 73 void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback);
  74 +
  75 +
75 76 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
... ... @@ -126,7 +126,15 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService {
126 126 List<DeviceChannel> deviceChannelList = new ArrayList<>();
127 127 if (channelReduces.size() > 0){
128 128 PlatformCatalog catalog = catalogManager.selectByPlatFormAndCatalogId(platform.getServerGBId(),catalogId);
129   - if (catalog == null || !catalogId.equals(platform.getDeviceGBId())) {
  129 + if (catalog == null && catalogId.equals(platform.getDeviceGBId())) {
  130 + for (ChannelReduce channelReduce : channelReduces) {
  131 + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
  132 + deviceChannel.setParental(0);
  133 + deviceChannel.setCivilCode(platform.getServerGBDomain());
  134 + deviceChannelList.add(deviceChannel);
  135 + }
  136 + return deviceChannelList;
  137 + } else if (catalog == null || !catalogId.equals(platform.getDeviceGBId())) {
130 138 logger.warn("未查询到目录{}的信息", catalogId);
131 139 return null;
132 140 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
... ... @@ -710,7 +710,19 @@ public class PlayServiceImpl implements IPlayService {
710 710 return;
711 711 }
712 712 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
713   - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false,false, device.getStreamModeForParam());
  713 + String stream = null;
  714 + if (newMediaServerItem.isRtpEnable()) {
  715 + String startTimeStr = startTime.replace("-", "")
  716 + .replace(":", "")
  717 + .replace(" ", "");
  718 + System.out.println(startTimeStr);
  719 + String endTimeTimeStr = endTime.replace("-", "")
  720 + .replace(":", "")
  721 + .replace(" ", "");
  722 + System.out.println(endTimeTimeStr);
  723 + stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr;
  724 + }
  725 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(), true, 0, false,false, device.getStreamModeForParam());
714 726 playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, callback);
715 727 }
716 728  
... ...
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
... ... @@ -53,6 +53,10 @@ public class DateUtil {
53 53 return formatter.format(formatterCompatibleISO8601.parse(formatTime));
54 54 }
55 55  
  56 + public static String urlToyyyy_MM_dd_HH_mm_ss(String formatTime) {
  57 + return formatter.format(urlFormatter.parse(formatTime));
  58 + }
  59 +
56 60 /**
57 61 * yyyy_MM_dd_HH_mm_ss 转时间戳
58 62 * @param formatTime
... ... @@ -82,6 +86,7 @@ public class DateUtil {
82 86 return urlFormatter.format(nowDateTime);
83 87 }
84 88  
  89 +
85 90 /**
86 91 * 格式校验
87 92 * @param timeStr 时间字符串
... ...