Commit 1d1f1748521930515fdab58e767c410d26108959

Authored by 648540858
1 parent 26739237

合并主线

src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
... ... @@ -4,7 +4,6 @@ import com.genersoft.iot.vmp.gb28181.bean.*;
4 4 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
5 5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
6 6 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
7   -import com.genersoft.iot.vmp.utils.DateUtil;
8 7 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
9 8 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
10 9 import com.genersoft.iot.vmp.service.IMediaServerService;
... ... @@ -26,12 +25,13 @@ import org.springframework.lang.Nullable;
26 25 import org.springframework.stereotype.Component;
27 26 import org.springframework.util.StringUtils;
28 27  
  28 +
  29 +import com.genersoft.iot.vmp.utils.DateUtil;
29 30 import javax.sip.*;
30 31 import javax.sip.address.SipURI;
31 32 import javax.sip.header.*;
32 33 import javax.sip.message.Request;
33 34 import java.lang.reflect.Field;
34   -import java.net.InetAddress;
35 35 import java.text.ParseException;
36 36 import java.util.ArrayList;
37 37 import java.util.HashSet;
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2  
3   -import com.alibaba.fastjson.JSON;
4 3 import com.alibaba.fastjson.JSONObject;
5   -import com.genersoft.iot.vmp.common.StreamInfo;
6 4 import com.genersoft.iot.vmp.conf.DynamicTask;
7 5 import com.genersoft.iot.vmp.gb28181.bean.*;
8 6 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
... ... @@ -22,7 +20,6 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
22 20 import gov.nist.javax.sip.message.SIPRequest;
23 21 import gov.nist.javax.sip.stack.SIPDialog;
24 22 import com.genersoft.iot.vmp.utils.SerializeUtils;
25   -import org.ehcache.shadow.org.terracotta.offheapstore.storage.IntegerStorageEngine;
26 23 import org.slf4j.Logger;
27 24 import org.slf4j.LoggerFactory;
28 25 import org.springframework.beans.factory.InitializingBean;
... ... @@ -37,7 +34,6 @@ import javax.sip.address.SipURI;
37 34 import javax.sip.header.CallIdHeader;
38 35 import javax.sip.header.FromHeader;
39 36 import javax.sip.header.HeaderAddress;
40   -import javax.sip.header.ToHeader;
41 37 import java.text.ParseException;
42 38 import java.util.*;
43 39  
... ... @@ -99,28 +95,28 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
99 95 @Override
100 96 public void process(RequestEvent evt) {
101 97 Dialog dialog = evt.getDialog();
102   - CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
  98 + CallIdHeader callIdHeader = (CallIdHeader) evt.getRequest().getHeader(CallIdHeader.NAME);
103 99 if (dialog == null) {
104 100 return;
105 101 }
106   - if (dialog.getState()== DialogState.CONFIRMED) {
  102 + if (dialog.getState() == DialogState.CONFIRMED) {
107 103 String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
108 104 logger.info("ACK请求: platformGbId->{}", platformGbId);
109 105 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformGbId);
110 106 // 取消设置的超时任务
111 107 dynamicTask.stop(callIdHeader.getCallId());
112 108 // String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
113   - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, null, null, callIdHeader.getCallId());
  109 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, null, null, callIdHeader.getCallId());
114 110 String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
115 111 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
116 112 logger.info("[收到ACK],开始使用{}向上级推流 {}/{}->{}:{}({})", sendRtpItem.isTcp() ? "TCP" : "UDP",
117 113 sendRtpItem.getApp(), sendRtpItem.getStreamId(),
118   - sendRtpItem.getIp() ,sendRtpItem.getPort(),
  114 + sendRtpItem.getIp(), sendRtpItem.getPort(),
119 115 sendRtpItem.getSsrc());
120 116 Map<String, Object> param = new HashMap<>();
121   - param.put("vhost","__defaultVhost__");
122   - param.put("app",sendRtpItem.getApp());
123   - param.put("stream",sendRtpItem.getStreamId());
  117 + param.put("vhost", "__defaultVhost__");
  118 + param.put("app", sendRtpItem.getApp());
  119 + param.put("stream", sendRtpItem.getStreamId());
124 120 param.put("ssrc", sendRtpItem.getSsrc());
125 121 param.put("src_port", sendRtpItem.getLocalPort());
126 122 param.put("pt", sendRtpItem.getPt());
... ... @@ -129,9 +125,9 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
129 125 JSONObject jsonObject;
130 126 if (sendRtpItem.isTcpActive()) {
131 127 jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
132   - }else {
  128 + } else {
133 129 param.put("is_udp", is_Udp);
134   - param.put("dst_url",sendRtpItem.getIp());
  130 + param.put("dst_url", sendRtpItem.getIp());
135 131 param.put("dst_port", sendRtpItem.getPort());
136 132 jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
137 133 }
... ... @@ -149,36 +145,37 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
149 145 String waiteStreamTimeoutTaskKey = "waite-stream-" + audioBroadcastCatch.getDeviceId() + audioBroadcastCatch.getChannelId();
150 146 dynamicTask.stop(waiteStreamTimeoutTaskKey);
151 147 }
152   - logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, " ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
  148 + logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
153 149 } else {
154   - logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"),JSONObject.toJSON(param));
  150 + logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSONObject.toJSON(param));
155 151 if (sendRtpItem.isOnlyAudio()) {
156 152 // 语音对讲
157 153 try {
158   - cmder.streamByeCmd((SIPDialog) evt.getDialog(), (SIPRequest)evt.getRequest(), null);
  154 + cmder.streamByeCmd((SIPDialog) evt.getDialog(), (SIPRequest) evt.getRequest(), null);
159 155 } catch (SipException e) {
160 156 throw new RuntimeException(e);
161 157 } catch (ParseException e) {
162 158 throw new RuntimeException(e);
163 159 }
164   - }else {
  160 + } else {
165 161 // 向上级平台
166 162 commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
167 163 }
168   - if (mediaInfo == null) {
169   - RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
170   - sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),
171   - sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
172   - sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
173   - redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, jsonObject->{
174   - startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, jsonObject, param, callIdHeader);
175   - });
176   - }else {
177   - JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
178   - startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, jsonObject, param, callIdHeader);
179   - }
  164 + if (mediaInfo == null) {
  165 + RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
  166 + sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),
  167 + sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
  168 + sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
  169 + redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {
  170 + startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, json, param, callIdHeader);
  171 + });
  172 + } else {
  173 + JSONObject startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  174 + startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, startSendRtpStreamResult, param, callIdHeader);
  175 + }
180 176  
181 177  
  178 + }
182 179 }
183 180 }
184 181 private void startSendRtpStreamHand(RequestEvent evt, SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
... ... @@ -19,15 +19,14 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
19 19 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
20 20 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
21 21 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
22   -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
23 22 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
24 23 import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
25 24 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
26 25 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
27 26 import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
28 27 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
29   -import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
30 28 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItemLite;
  29 +import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
31 30 import com.genersoft.iot.vmp.service.IMediaServerService;
32 31 import com.genersoft.iot.vmp.service.IPlayService;
33 32 import com.genersoft.iot.vmp.service.IStreamPushService;
... ... @@ -58,8 +57,6 @@ import javax.sip.message.Request;
58 57 import javax.sip.message.Response;
59 58 import java.text.ParseException;
60 59 import java.time.Instant;
61   -import java.util.Date;
62   -import java.util.List;
63 60 import java.util.Vector;
64 61  
65 62 /**
... ... @@ -109,9 +106,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
109 106 @Autowired
110 107 private ZLMRESTfulUtils zlmresTfulUtils;
111 108  
112   - @Autowired
113   - private IMediaServerService mediaServerService;
114   -
115 109 @Autowired
116 110 private SIPProcessorObserver sipProcessorObserver;
117 111  
... ... @@ -171,7 +165,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
171 165 // 查询请求是否来自上级平台\设备
172 166 ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
173 167 if (platform == null) {
174   - inviteFromDeviceHandle(evt, requesterId);
  168 + inviteFromDeviceHandle(evt, requesterId, channelId);
175 169 } else {
176 170 // 查询平台下是否有该通道
177 171 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
... ... @@ -724,10 +718,16 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
724 718 }
725 719 }
726 720  
727   - public void inviteFromDeviceHandle(RequestEvent evt, String requesterId) throws InvalidArgumentException, ParseException, SipException, SdpException {
  721 + public void inviteFromDeviceHandle(RequestEvent evt, String requesterId, String channelId1) throws InvalidArgumentException, ParseException, SipException, SdpException {
728 722  
729 723 // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
730 724 Device device = redisCatchStorage.getDevice(requesterId);
  725 + AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(requesterId, channelId1);
  726 + if (audioBroadcastCatch == null) {
  727 + logger.warn("来自设备的Invite请求非语音广播,已忽略");
  728 + responseAck(evt, Response.FORBIDDEN);
  729 + return;
  730 + }
731 731 Request request = evt.getRequest();
732 732 if (device != null) {
733 733 logger.info("收到设备" + requesterId + "的语音广播Invite请求");
... ... @@ -740,7 +740,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
740 740 int ssrcIndex = contentString.indexOf("y=");
741 741 if (ssrcIndex > 0) {
742 742 substring = contentString.substring(0, ssrcIndex);
743   - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  743 + ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim();
744 744 }
745 745 ssrcIndex = substring.indexOf("f=");
746 746 if (ssrcIndex > 0) {
... ... @@ -750,13 +750,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
750 750  
751 751 // 获取支持的格式
752 752 Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  753 +
753 754 // 查看是否支持PS 负载96
754 755 int port = -1;
755   - //boolean recvonly = false;
756 756 boolean mediaTransmissionTCP = false;
757 757 Boolean tcpActive = null;
758 758 for (int i = 0; i < mediaDescriptions.size(); i++) {
759   - MediaDescription mediaDescription = (MediaDescription) mediaDescriptions.get(i);
  759 + MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
760 760 Media media = mediaDescription.getMedia();
761 761  
762 762 Vector mediaFormats = media.getMediaFormats(false);
... ... @@ -784,233 +784,248 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
784 784 responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
785 785 return;
786 786 }
787   - String username = sdp.getOrigin().getUsername();
788 787 String addressStr = sdp.getOrigin().getAddress();
789   - logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc);
  788 + logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", requesterId, addressStr, port, ssrc);
  789 +
  790 + MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device);
  791 + if (mediaServerItem == null) {
  792 + logger.warn("未找到可用的zlm");
  793 + responseAck(evt, Response.BUSY_HERE);
  794 + return;
  795 + }
  796 + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
  797 + device.getDeviceId(), audioBroadcastCatch.getChannelId(),
  798 + mediaTransmissionTCP);
  799 + if (sendRtpItem == null) {
  800 + logger.warn("服务器端口资源不足");
  801 + responseAck(evt, Response.BUSY_HERE);
  802 + return;
  803 + }
  804 + sendRtpItem.setTcp(mediaTransmissionTCP);
  805 + if (tcpActive != null) {
  806 + sendRtpItem.setTcpActive(tcpActive);
  807 + }
  808 + String app = "broadcast";
  809 + String stream = device.getDeviceId() + "_" + audioBroadcastCatch.getChannelId();
  810 +
  811 + CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
  812 + sendRtpItem.setPlayType(InviteStreamType.PLAY);
  813 + sendRtpItem.setCallId(callIdHeader.getCallId());
  814 + sendRtpItem.setPlatformId(requesterId);
  815 + sendRtpItem.setStatus(1);
  816 + sendRtpItem.setApp(app);
  817 + sendRtpItem.setStreamId(stream);
  818 + sendRtpItem.setPt(8);
  819 + sendRtpItem.setUsePs(false);
  820 + sendRtpItem.setOnlyAudio(true);
  821 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  822 +
  823 + // hook监听等待设备推流上来
  824 + // 添加订阅
  825 + JSONObject subscribeKey = new JSONObject();
  826 + subscribeKey.put("app", app);
  827 + subscribeKey.put("stream", stream);
  828 + subscribeKey.put("regist", true);
  829 + subscribeKey.put("schema", "rtmp");
  830 + subscribeKey.put("mediaServerId", mediaServerItem.getId());
  831 + String finalSsrc = ssrc;
  832 + // 流已经存在时直接推流
  833 + JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtsp", stream);
  834 + JSONArray tracks = mediaInfo.getJSONArray("tracks");
  835 + Integer codecId = null;
  836 + if (tracks != null && tracks.size() > 0) {
  837 + for (int i = 0; i < tracks.size(); i++) {
  838 + MediaItem.MediaTrack track = JSON.toJavaObject((JSON)tracks.get(i),MediaItem.MediaTrack.class);
  839 + if (track.getCodecType() == 1) {
  840 + codecId = track.getCodecId();
  841 + break;
  842 + }
  843 + }
  844 + }
  845 + if ((mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"))) {
  846 + logger.info("发现已经在推流");
  847 + sendRtpItem.setStatus(2);
  848 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  849 + StringBuffer content = new StringBuffer(200);
  850 + content.append("v=0\r\n");
  851 + content.append("o="+ config.getId() +" "+ sdp.getOrigin().getSessionId() +" " + sdp.getOrigin().getSessionVersion() + " IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  852 + content.append("s=Play\r\n");
  853 + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  854 + content.append("t=0 0\r\n");
  855 + if (codecId == null) {
  856 + if (mediaTransmissionTCP) {
  857 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");
  858 + }else {
  859 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
  860 + }
  861 +
  862 + content.append("a=rtpmap:8 PCMA/8000\r\n");
  863 + }else {
  864 + if (codecId == 4) {
  865 + if (mediaTransmissionTCP) {
  866 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 0\r\n");
  867 + }else {
  868 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 0\r\n");
  869 + }
  870 + content.append("a=rtpmap:0 PCMU/8000\r\n");
  871 + }else {
  872 + if (mediaTransmissionTCP) {
  873 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");
  874 + }else {
  875 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
  876 + }
  877 + content.append("a=rtpmap:8 PCMA/8000\r\n");
  878 + }
  879 + }
  880 + if (sendRtpItem.isTcp()) {
  881 + content.append("a=connection:new\r\n");
  882 + if (!sendRtpItem.isTcpActive()) {
  883 + content.append("a=setup:active\r\n");
  884 + }else {
  885 + content.append("a=setup:passive\r\n");
  886 + }
  887 + }
  888 + content.append("a=sendonly\r\n");
  889 + content.append("y="+ finalSsrc + "\r\n");
  890 + content.append("f=v/////a/1/8/1\r\n");
  891 +
  892 + ParentPlatform parentPlatform = new ParentPlatform();
  893 + parentPlatform.setServerIP(device.getIp());
  894 + parentPlatform.setServerPort(device.getPort());
  895 + parentPlatform.setServerGBId(device.getDeviceId());
  896 + try {
  897 + responseSdpAck(evt, content.toString(), parentPlatform);
  898 + Dialog dialog = evt.getDialog();
  899 + audioBroadcastCatch.setDialog((SIPDialog) dialog);
  900 + audioBroadcastCatch.setRequest((SIPRequest) request);
  901 + audioBroadcastManager.update(audioBroadcastCatch);
  902 + } catch (SipException e) {
  903 + throw new RuntimeException(e);
  904 + } catch (InvalidArgumentException e) {
  905 + throw new RuntimeException(e);
  906 + } catch (ParseException e) {
  907 + throw new RuntimeException(e);
  908 + }
  909 + }else {
  910 + // 流不存在时监听流上线
  911 + // 设置等待推流的超时; 默认20s
  912 + String waiteStreamTimeoutTaskKey = "waite-stream-" + device.getDeviceId() + audioBroadcastCatch.getChannelId();
  913 + dynamicTask.startDelay(waiteStreamTimeoutTaskKey, ()->{
  914 + logger.info("等待推流超时: {}/{}", app, stream);
  915 + subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
  916 + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  917 + // 发送bye
  918 + try {
  919 + responseAck(evt, Response.BUSY_HERE);
  920 + } catch (SipException e) {
  921 + throw new RuntimeException(e);
  922 + } catch (InvalidArgumentException e) {
  923 + throw new RuntimeException(e);
  924 + } catch (ParseException e) {
  925 + throw new RuntimeException(e);
  926 + }
  927 + }, 20*1000);
  928 +
  929 + boolean finalMediaTransmissionTCP = mediaTransmissionTCP;
  930 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  931 + (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  932 + logger.info("收到语音对讲推流");
  933 + MediaItem mediaItem = JSON.toJavaObject(json, MediaItem.class);
  934 + Integer audioCodecId = null;
  935 + if (mediaItem.getTracks() != null && mediaItem.getTracks().size() > 0) {
  936 + for (int i = 0; i < mediaItem.getTracks().size(); i++) {
  937 + MediaItem.MediaTrack mediaTrack = mediaItem.getTracks().get(i);
  938 + if (mediaTrack.getCodecType() == 1) {
  939 + audioCodecId = mediaTrack.getCodecId();
  940 + break;
  941 + }
  942 + }
  943 + }
790 944  
  945 + try {
  946 + sendRtpItem.setStatus(2);
  947 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  948 + StringBuffer content = new StringBuffer(200);
  949 + content.append("v=0\r\n");
  950 + content.append("o="+ config.getId() +" "+ sdp.getOrigin().getSessionId() +" " + sdp.getOrigin().getSessionVersion() + " IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  951 + content.append("s=Play\r\n");
  952 + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  953 + content.append("t=0 0\r\n");
  954 + if (audioCodecId == null) {
  955 + if (finalMediaTransmissionTCP) {
  956 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");
  957 + }else {
  958 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
  959 + }
  960 +
  961 + content.append("a=rtpmap:8 PCMA/8000\r\n");
  962 + }else {
  963 + if (audioCodecId == 4) {
  964 + if (finalMediaTransmissionTCP) {
  965 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 0\r\n");
  966 + }else {
  967 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 0\r\n");
  968 + }
  969 + content.append("a=rtpmap:0 PCMU/8000\r\n");
  970 + }else {
  971 + if (finalMediaTransmissionTCP) {
  972 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");
  973 + }else {
  974 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
  975 + }
  976 + content.append("a=rtpmap:8 PCMA/8000\r\n");
  977 + }
  978 + }
  979 + content.append("a=sendonly\r\n");
  980 + if (sendRtpItem.isTcp()) {
  981 + content.append("a=connection:new\r\n");
  982 + if (!sendRtpItem.isTcpActive()) {
  983 + content.append("a=setup:active\r\n");
  984 + }else {
  985 + content.append("a=setup:passive\r\n");
  986 + }
  987 + }
  988 + content.append("y="+ finalSsrc + "\r\n");
  989 + content.append("f=v/////a/1/8/1\r\n");
  990 +
  991 + ParentPlatform parentPlatform = new ParentPlatform();
  992 + parentPlatform.setServerIP(device.getIp());
  993 + parentPlatform.setServerPort(device.getPort());
  994 + parentPlatform.setServerGBId(device.getDeviceId());
  995 +
  996 + responseSdpAck(evt, content.toString(), parentPlatform);
  997 + Dialog dialog = evt.getDialog();
  998 + audioBroadcastCatch.setDialog((SIPDialog) dialog);
  999 + audioBroadcastCatch.setRequest((SIPRequest) request);
  1000 + audioBroadcastManager.update(audioBroadcastCatch);
  1001 + } catch (SipException e) {
  1002 + throw new RuntimeException(e);
  1003 + } catch (InvalidArgumentException e) {
  1004 + throw new RuntimeException(e);
  1005 + } catch (ParseException e) {
  1006 + throw new RuntimeException(e);
  1007 + } catch (SdpParseException e) {
  1008 + throw new RuntimeException(e);
  1009 + }
  1010 + });
  1011 + }
  1012 + String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId();
  1013 + WVPResult<AudioBroadcastResult> wvpResult = new WVPResult<>();
  1014 + wvpResult.setCode(0);
  1015 + wvpResult.setMsg("success");
  1016 + AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult();
  1017 + audioBroadcastResult.setApp(app);
  1018 + audioBroadcastResult.setStream(stream);
  1019 + audioBroadcastResult.setMediaServerItem(new MediaServerItemLite(mediaServerItem));
  1020 + audioBroadcastResult.setCodec("G.711");
  1021 + wvpResult.setData(audioBroadcastResult);
  1022 + RequestMessage requestMessage = new RequestMessage();
  1023 + requestMessage.setKey(key);
  1024 + requestMessage.setData(wvpResult);
  1025 + resultHolder.invokeAllResult(requestMessage);
791 1026 } else {
792 1027 logger.warn("来自无效设备/平台的请求");
793 1028 responseAck(evt, Response.BAD_REQUEST);
794 1029 }
795 1030 }
796   - CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
797   - sendRtpItem.setPlayType(InviteStreamType.PLAY);
798   - sendRtpItem.setCallId(callIdHeader.getCallId());
799   - sendRtpItem.setPlatformId(requesterId);
800   - sendRtpItem.setStatus(1);
801   - sendRtpItem.setApp(app);
802   - sendRtpItem.setStreamId(stream);
803   - sendRtpItem.setPt(8);
804   - sendRtpItem.setUsePs(false);
805   - sendRtpItem.setOnlyAudio(true);
806   - redisCatchStorage.updateSendRTPSever(sendRtpItem);
807   -
808   - // hook监听等待设备推流上来
809   - // 添加订阅
810   - JSONObject subscribeKey = new JSONObject();
811   - subscribeKey.put("app", app);
812   - subscribeKey.put("stream", stream);
813   - subscribeKey.put("regist", true);
814   - subscribeKey.put("schema", "rtmp");
815   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
816   - String finalSsrc = ssrc;
817   - // 流已经存在时直接推流
818   - JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtsp", stream);
819   - JSONArray tracks = mediaInfo.getJSONArray("tracks");
820   - Integer codecId = null;
821   - if (tracks != null && tracks.size() > 0) {
822   - for (int i = 0; i < tracks.size(); i++) {
823   - MediaItem.MediaTrack track = JSON.toJavaObject((JSON)tracks.get(i),MediaItem.MediaTrack.class);
824   - if (track.getCodecType() == 1) {
825   - codecId = track.getCodecId();
826   - break;
827   - }
828   - }
829   - }
830   - if ((mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"))) {
831   - logger.info("发现已经在推流");
832   - sendRtpItem.setStatus(2);
833   - redisCatchStorage.updateSendRTPSever(sendRtpItem);
834   - StringBuffer content = new StringBuffer(200);
835   - content.append("v=0\r\n");
836   - content.append("o="+ config.getId() +" "+ sdp.getOrigin().getSessionId() +" " + sdp.getOrigin().getSessionVersion() + " IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
837   - content.append("s=Play\r\n");
838   - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
839   - content.append("t=0 0\r\n");
840   - if (codecId == null) {
841   - if (mediaTransmissionTCP) {
842   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");
843   - }else {
844   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
845   - }
846   -
847   - content.append("a=rtpmap:8 PCMA/8000\r\n");
848   - }else {
849   - if (codecId == 4) {
850   - if (mediaTransmissionTCP) {
851   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 0\r\n");
852   - }else {
853   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 0\r\n");
854   - }
855   - content.append("a=rtpmap:0 PCMU/8000\r\n");
856   - }else {
857   - if (mediaTransmissionTCP) {
858   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");
859   - }else {
860   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
861   - }
862   - content.append("a=rtpmap:8 PCMA/8000\r\n");
863   - }
864   - }
865   - if (sendRtpItem.isTcp()) {
866   - content.append("a=connection:new\r\n");
867   - if (!sendRtpItem.isTcpActive()) {
868   - content.append("a=setup:active\r\n");
869   - }else {
870   - content.append("a=setup:passive\r\n");
871   - }
872   - }
873   - content.append("a=sendonly\r\n");
874   - content.append("y="+ finalSsrc + "\r\n");
875   - content.append("f=v/////a/1/8/1\r\n");
876   -
877   - ParentPlatform parentPlatform = new ParentPlatform();
878   - parentPlatform.setServerIP(device.getIp());
879   - parentPlatform.setServerPort(device.getPort());
880   - parentPlatform.setServerGBId(device.getDeviceId());
881   - try {
882   - responseSdpAck(evt, content.toString(), parentPlatform);
883   - Dialog dialog = evt.getDialog();
884   - audioBroadcastCatch.setDialog((SIPDialog) dialog);
885   - audioBroadcastCatch.setRequest((SIPRequest) request);
886   - audioBroadcastManager.update(audioBroadcastCatch);
887   - } catch (SipException e) {
888   - throw new RuntimeException(e);
889   - } catch (InvalidArgumentException e) {
890   - throw new RuntimeException(e);
891   - } catch (ParseException e) {
892   - throw new RuntimeException(e);
893   - }
894   - }else {
895   - // 流不存在时监听流上线
896   - // 设置等待推流的超时; 默认20s
897   - String waiteStreamTimeoutTaskKey = "waite-stream-" + device.getDeviceId() + audioBroadcastCatch.getChannelId();
898   - dynamicTask.startDelay(waiteStreamTimeoutTaskKey, ()->{
899   - logger.info("等待推流超时: {}/{}", app, stream);
900   - subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
901   - playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
902   - // 发送bye
903   - try {
904   - responseAck(evt, Response.BUSY_HERE);
905   - } catch (SipException e) {
906   - throw new RuntimeException(e);
907   - } catch (InvalidArgumentException e) {
908   - throw new RuntimeException(e);
909   - } catch (ParseException e) {
910   - throw new RuntimeException(e);
911   - }
912   - }, 20*1000);
913   -
914   - boolean finalMediaTransmissionTCP = mediaTransmissionTCP;
915   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
916   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
917   - logger.info("收到语音对讲推流");
918   - MediaItem mediaItem = JSON.toJavaObject(json, MediaItem.class);
919   - Integer audioCodecId = null;
920   - if (mediaItem.getTracks() != null && mediaItem.getTracks().size() > 0) {
921   - for (int i = 0; i < mediaItem.getTracks().size(); i++) {
922   - MediaItem.MediaTrack mediaTrack = mediaItem.getTracks().get(i);
923   - if (mediaTrack.getCodecType() == 1) {
924   - audioCodecId = mediaTrack.getCodecId();
925   - break;
926   - }
927   - }
928   - }
929   -
930   - try {
931   - sendRtpItem.setStatus(2);
932   - redisCatchStorage.updateSendRTPSever(sendRtpItem);
933   - StringBuffer content = new StringBuffer(200);
934   - content.append("v=0\r\n");
935   - content.append("o="+ config.getId() +" "+ sdp.getOrigin().getSessionId() +" " + sdp.getOrigin().getSessionVersion() + " IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
936   - content.append("s=Play\r\n");
937   - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
938   - content.append("t=0 0\r\n");
939   - if (audioCodecId == null) {
940   - if (finalMediaTransmissionTCP) {
941   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");
942   - }else {
943   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
944   - }
945   -
946   - content.append("a=rtpmap:8 PCMA/8000\r\n");
947   - }else {
948   - if (audioCodecId == 4) {
949   - if (finalMediaTransmissionTCP) {
950   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 0\r\n");
951   - }else {
952   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 0\r\n");
953   - }
954   - content.append("a=rtpmap:0 PCMU/8000\r\n");
955   - }else {
956   - if (finalMediaTransmissionTCP) {
957   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");
958   - }else {
959   - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
960   - }
961   - content.append("a=rtpmap:8 PCMA/8000\r\n");
962   - }
963   - }
964   - content.append("a=sendonly\r\n");
965   - if (sendRtpItem.isTcp()) {
966   - content.append("a=connection:new\r\n");
967   - if (!sendRtpItem.isTcpActive()) {
968   - content.append("a=setup:active\r\n");
969   - }else {
970   - content.append("a=setup:passive\r\n");
971   - }
972   - }
973   - content.append("y="+ finalSsrc + "\r\n");
974   - content.append("f=v/////a/1/8/1\r\n");
975   -
976   - ParentPlatform parentPlatform = new ParentPlatform();
977   - parentPlatform.setServerIP(device.getIp());
978   - parentPlatform.setServerPort(device.getPort());
979   - parentPlatform.setServerGBId(device.getDeviceId());
980   -
981   - responseSdpAck(evt, content.toString(), parentPlatform);
982   - Dialog dialog = evt.getDialog();
983   - audioBroadcastCatch.setDialog((SIPDialog) dialog);
984   - audioBroadcastCatch.setRequest((SIPRequest) request);
985   - audioBroadcastManager.update(audioBroadcastCatch);
986   - } catch (SipException e) {
987   - throw new RuntimeException(e);
988   - } catch (InvalidArgumentException e) {
989   - throw new RuntimeException(e);
990   - } catch (ParseException e) {
991   - throw new RuntimeException(e);
992   - } catch (SdpParseException e) {
993   - throw new RuntimeException(e);
994   - }
995   - });
996   - }
997   - String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId();
998   - WVPResult<AudioBroadcastResult> wvpResult = new WVPResult<>();
999   - wvpResult.setCode(0);
1000   - wvpResult.setMsg("success");
1001   - AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult();
1002   - audioBroadcastResult.setApp(app);
1003   - audioBroadcastResult.setStream(stream);
1004   - audioBroadcastResult.setMediaServerItem(new MediaServerItemLite(mediaServerItem));
1005   - audioBroadcastResult.setCodec("G.711");
1006   - wvpResult.setData(audioBroadcastResult);
1007   - RequestMessage requestMessage = new RequestMessage();
1008   - requestMessage.setKey(key);
1009   - requestMessage.setData(wvpResult);
1010   - resultHolder.invokeAllResult(requestMessage);
1011   - } else {
1012   - logger.warn("来自无效设备/平台的请求");
1013   - responseAck(evt, Response.BAD_REQUEST);
1014   - }
1015   - }
1016 1031 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
1 1 package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
4   -import com.genersoft.iot.vmp.gb28181.bean.Device;
5 4 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
6 5 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
7 6 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
... ... @@ -6,7 +6,6 @@ import com.alibaba.fastjson.JSONObject;
6 6 import com.genersoft.iot.vmp.common.VideoManagerConstants;
7 7 import com.genersoft.iot.vmp.conf.SipConfig;
8 8 import com.genersoft.iot.vmp.conf.UserSetting;
9   -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
10 9 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
11 10 import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
12 11 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
... ... @@ -34,11 +33,8 @@ import org.springframework.transaction.TransactionDefinition;
34 33 import org.springframework.transaction.TransactionStatus;
35 34 import org.springframework.util.StringUtils;
36 35  
37   -import java.text.ParseException;
38   -import java.text.SimpleDateFormat;
39 36 import java.time.LocalDateTime;
40 37 import java.util.*;
41   -import java.util.stream.Collectors;
42 38  
43 39 /**
44 40 * 媒体服务器节点管理
... ...
web_src/package-lock.json
... ... @@ -50,7 +50,7 @@
50 50 "postcss-url": "^7.2.1",
51 51 "rimraf": "^2.6.0",
52 52 "semver": "^5.3.0",
53   - "shelljs": "^0.7.6",
  53 + "shelljs": "^0.8.5",
54 54 "uglifyjs-webpack-plugin": "^1.1.1",
55 55 "url-loader": "^0.5.8",
56 56 "vue-loader": "^13.3.0",
... ... @@ -11655,9 +11655,9 @@
11655 11655 }
11656 11656 },
11657 11657 "node_modules/shelljs": {
11658   - "version": "0.7.8",
11659   - "resolved": "https://registry.npm.taobao.org/shelljs/download/shelljs-0.7.8.tgz",
11660   - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
  11658 + "version": "0.8.5",
  11659 + "resolved": "https://registry.npmmirror.com/shelljs/-/shelljs-0.8.5.tgz",
  11660 + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
11661 11661 "dev": true,
11662 11662 "dependencies": {
11663 11663 "glob": "^7.0.0",
... ... @@ -11668,8 +11668,7 @@
11668 11668 "shjs": "bin/shjs"
11669 11669 },
11670 11670 "engines": {
11671   - "iojs": "*",
11672   - "node": ">=0.11.0"
  11671 + "node": ">=4"
11673 11672 }
11674 11673 },
11675 11674 "node_modules/shellwords": {
... ... @@ -24156,9 +24155,9 @@
24156 24155 "dev": true
24157 24156 },
24158 24157 "shelljs": {
24159   - "version": "0.7.8",
24160   - "resolved": "https://registry.npm.taobao.org/shelljs/download/shelljs-0.7.8.tgz",
24161   - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
  24158 + "version": "0.8.5",
  24159 + "resolved": "https://registry.npmmirror.com/shelljs/-/shelljs-0.8.5.tgz",
  24160 + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
24162 24161 "dev": true,
24163 24162 "requires": {
24164 24163 "glob": "^7.0.0",
... ...