Commit 668dc8f0dd8b667a95838eb5d0083a101aa2b6b0
Merge branch '2.6.8' into wvp-28181-2.0
# 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/ZLMHttpHookListener.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java # src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java # src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java # src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java # src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java
Showing
8 changed files
with
282 additions
and
95 deletions
sql/2.6.8补丁更新.sql
0 → 100644
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| ... | ... | @@ -158,6 +158,7 @@ public class VideoManagerConstants { |
| 158 | 158 | public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; |
| 159 | 159 | public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; |
| 160 | 160 | public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_"; |
| 161 | + public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_"; | |
| 161 | 162 | |
| 162 | 163 | /** |
| 163 | 164 | * Redis Const | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
| ... | ... | @@ -234,4 +234,11 @@ public class MediaConfig{ |
| 234 | 234 | return false; |
| 235 | 235 | } |
| 236 | 236 | |
| 237 | + public String getRtpSendPortRange() { | |
| 238 | + return rtpSendPortRange; | |
| 239 | + } | |
| 240 | + | |
| 241 | + public void setRtpSendPortRange(String rtpSendPortRange) { | |
| 242 | + this.rtpSendPortRange = rtpSendPortRange; | |
| 243 | + } | |
| 237 | 244 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java
| ... | ... | @@ -86,7 +86,10 @@ public class ZLMServerFactory { |
| 86 | 86 | }else { |
| 87 | 87 | param.put("port", port); |
| 88 | 88 | } |
| 89 | - param.put("ssrc", ssrc); | |
| 89 | + if (ssrc != 0) { | |
| 90 | + param.put("ssrc", ssrc); | |
| 91 | + } | |
| 92 | + | |
| 90 | 93 | JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param); |
| 91 | 94 | logger.info(JSONObject.toJSONString(openRtpServerResultJson)); |
| 92 | 95 | if (openRtpServerResultJson != null) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
| ... | ... | @@ -51,5 +51,13 @@ public class HookResultForOnPublish extends HookResult{ |
| 51 | 51 | this.mp4_save_path = mp4_save_path; |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | - | |
| 54 | + @Override | |
| 55 | + public String toString() { | |
| 56 | + return "HookResultForOnPublish{" + | |
| 57 | + "enable_audio=" + enable_audio + | |
| 58 | + ", enable_mp4=" + enable_mp4 + | |
| 59 | + ", mp4_max_second=" + mp4_max_second + | |
| 60 | + ", mp4_save_path='" + mp4_save_path + '\'' + | |
| 61 | + '}'; | |
| 62 | + } | |
| 55 | 63 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/OtherRtpSendInfo.java
| ... | ... | @@ -5,12 +5,17 @@ public class OtherRtpSendInfo { |
| 5 | 5 | /** |
| 6 | 6 | * 发流IP |
| 7 | 7 | */ |
| 8 | - private String ip; | |
| 8 | + private String sendLocalIp; | |
| 9 | 9 | |
| 10 | 10 | /** |
| 11 | - * 发流端口 | |
| 11 | + * 音频发流端口 | |
| 12 | 12 | */ |
| 13 | - private int port; | |
| 13 | + private int sendLocalPortForAudio; | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * 视频发流端口 | |
| 17 | + */ | |
| 18 | + private int sendLocalPortForVideo; | |
| 14 | 19 | |
| 15 | 20 | /** |
| 16 | 21 | * 收流IP |
| ... | ... | @@ -18,9 +23,14 @@ public class OtherRtpSendInfo { |
| 18 | 23 | private String receiveIp; |
| 19 | 24 | |
| 20 | 25 | /** |
| 21 | - * 收流端口 | |
| 26 | + * 音频收流端口 | |
| 27 | + */ | |
| 28 | + private int receivePortForAudio; | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * 视频收流端口 | |
| 22 | 32 | */ |
| 23 | - private int receivePort; | |
| 33 | + private int receivePortForVideo; | |
| 24 | 34 | |
| 25 | 35 | /** |
| 26 | 36 | * 会话ID |
| ... | ... | @@ -48,23 +58,6 @@ public class OtherRtpSendInfo { |
| 48 | 58 | private String pushSSRC; |
| 49 | 59 | |
| 50 | 60 | |
| 51 | - | |
| 52 | - public String getIp() { | |
| 53 | - return ip; | |
| 54 | - } | |
| 55 | - | |
| 56 | - public void setIp(String ip) { | |
| 57 | - this.ip = ip; | |
| 58 | - } | |
| 59 | - | |
| 60 | - public int getPort() { | |
| 61 | - return port; | |
| 62 | - } | |
| 63 | - | |
| 64 | - public void setPort(int port) { | |
| 65 | - this.port = port; | |
| 66 | - } | |
| 67 | - | |
| 68 | 61 | public String getReceiveIp() { |
| 69 | 62 | return receiveIp; |
| 70 | 63 | } |
| ... | ... | @@ -73,12 +66,20 @@ public class OtherRtpSendInfo { |
| 73 | 66 | this.receiveIp = receiveIp; |
| 74 | 67 | } |
| 75 | 68 | |
| 76 | - public int getReceivePort() { | |
| 77 | - return receivePort; | |
| 69 | + public int getReceivePortForAudio() { | |
| 70 | + return receivePortForAudio; | |
| 71 | + } | |
| 72 | + | |
| 73 | + public void setReceivePortForAudio(int receivePortForAudio) { | |
| 74 | + this.receivePortForAudio = receivePortForAudio; | |
| 75 | + } | |
| 76 | + | |
| 77 | + public int getReceivePortForVideo() { | |
| 78 | + return receivePortForVideo; | |
| 78 | 79 | } |
| 79 | 80 | |
| 80 | - public void setReceivePort(int receivePort) { | |
| 81 | - this.receivePort = receivePort; | |
| 81 | + public void setReceivePortForVideo(int receivePortForVideo) { | |
| 82 | + this.receivePortForVideo = receivePortForVideo; | |
| 82 | 83 | } |
| 83 | 84 | |
| 84 | 85 | public String getCallId() { |
| ... | ... | @@ -121,15 +122,45 @@ public class OtherRtpSendInfo { |
| 121 | 122 | this.pushSSRC = pushSSRC; |
| 122 | 123 | } |
| 123 | 124 | |
| 125 | + | |
| 126 | + public String getSendLocalIp() { | |
| 127 | + return sendLocalIp; | |
| 128 | + } | |
| 129 | + | |
| 130 | + public void setSendLocalIp(String sendLocalIp) { | |
| 131 | + this.sendLocalIp = sendLocalIp; | |
| 132 | + } | |
| 133 | + | |
| 134 | + public int getSendLocalPortForAudio() { | |
| 135 | + return sendLocalPortForAudio; | |
| 136 | + } | |
| 137 | + | |
| 138 | + public void setSendLocalPortForAudio(int sendLocalPortForAudio) { | |
| 139 | + this.sendLocalPortForAudio = sendLocalPortForAudio; | |
| 140 | + } | |
| 141 | + | |
| 142 | + public int getSendLocalPortForVideo() { | |
| 143 | + return sendLocalPortForVideo; | |
| 144 | + } | |
| 145 | + | |
| 146 | + public void setSendLocalPortForVideo(int sendLocalPortForVideo) { | |
| 147 | + this.sendLocalPortForVideo = sendLocalPortForVideo; | |
| 148 | + } | |
| 149 | + | |
| 124 | 150 | @Override |
| 125 | 151 | public String toString() { |
| 126 | 152 | return "OtherRtpSendInfo{" + |
| 127 | - "ip='" + ip + '\'' + | |
| 128 | - ", port=" + port + | |
| 153 | + "sendLocalIp='" + sendLocalIp + '\'' + | |
| 154 | + ", sendLocalPortForAudio=" + sendLocalPortForAudio + | |
| 155 | + ", sendLocalPortForVideo=" + sendLocalPortForVideo + | |
| 129 | 156 | ", receiveIp='" + receiveIp + '\'' + |
| 130 | - ", receivePort=" + receivePort + | |
| 157 | + ", receivePortForAudio=" + receivePortForAudio + | |
| 158 | + ", receivePortForVideo=" + receivePortForVideo + | |
| 131 | 159 | ", callId='" + callId + '\'' + |
| 132 | 160 | ", stream='" + stream + '\'' + |
| 161 | + ", pushApp='" + pushApp + '\'' + | |
| 162 | + ", pushStream='" + pushStream + '\'' + | |
| 163 | + ", pushSSRC='" + pushSSRC + '\'' + | |
| 133 | 164 | '}'; |
| 134 | 165 | } |
| 135 | 166 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java
| ... | ... | @@ -3,21 +3,22 @@ package com.genersoft.iot.vmp.vmanager.rtp; |
| 3 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | 4 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 5 | 5 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 6 | -import com.genersoft.iot.vmp.conf.SipConfig; | |
| 7 | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 8 | -import com.genersoft.iot.vmp.conf.VersionInfo; | |
| 9 | 7 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 10 | 8 | import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; |
| 11 | 9 | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; |
| 10 | +import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; | |
| 11 | +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; | |
| 12 | 12 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| 13 | 13 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 14 | 14 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; |
| 15 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | |
| 15 | 16 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 16 | 17 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRtpServerTimeoutHookParam; |
| 17 | 18 | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| 18 | 19 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 19 | 20 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 20 | -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 21 | +import com.genersoft.iot.vmp.utils.redis.RedisUtil; | |
| 21 | 22 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 22 | 23 | import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; |
| 23 | 24 | import io.swagger.v3.oas.annotations.Operation; |
| ... | ... | @@ -28,14 +29,16 @@ import okhttp3.Request; |
| 28 | 29 | import org.slf4j.Logger; |
| 29 | 30 | import org.slf4j.LoggerFactory; |
| 30 | 31 | import org.springframework.beans.factory.annotation.Autowired; |
| 31 | -import org.springframework.beans.factory.annotation.Value; | |
| 32 | 32 | import org.springframework.data.redis.core.RedisTemplate; |
| 33 | 33 | import org.springframework.util.ObjectUtils; |
| 34 | 34 | import org.springframework.web.bind.annotation.*; |
| 35 | 35 | |
| 36 | 36 | import java.io.IOException; |
| 37 | 37 | import java.util.HashMap; |
| 38 | +import java.util.List; | |
| 38 | 39 | import java.util.Map; |
| 40 | +import java.util.UUID; | |
| 41 | +import java.util.concurrent.TimeUnit; | |
| 39 | 42 | import java.util.concurrent.TimeUnit; |
| 40 | 43 | |
| 41 | 44 | @SuppressWarnings("rawtypes") |
| ... | ... | @@ -60,21 +63,12 @@ public class RtpController { |
| 60 | 63 | private IMediaServerService mediaServerService; |
| 61 | 64 | |
| 62 | 65 | @Autowired |
| 63 | - private VersionInfo versionInfo; | |
| 64 | - | |
| 65 | - @Autowired | |
| 66 | - private SipConfig sipConfig; | |
| 66 | + private SendRtpPortManager sendRtpPortManager; | |
| 67 | 67 | |
| 68 | 68 | @Autowired |
| 69 | 69 | private UserSetting userSetting; |
| 70 | 70 | |
| 71 | 71 | @Autowired |
| 72 | - private IDeviceService deviceService; | |
| 73 | - | |
| 74 | - @Autowired | |
| 75 | - private IDeviceChannelService channelService; | |
| 76 | - | |
| 77 | - @Autowired | |
| 78 | 72 | private DynamicTask dynamicTask; |
| 79 | 73 | |
| 80 | 74 | |
| ... | ... | @@ -82,14 +76,6 @@ public class RtpController { |
| 82 | 76 | private RedisTemplate<Object, Object> redisTemplate; |
| 83 | 77 | |
| 84 | 78 | |
| 85 | - @Value("${server.port}") | |
| 86 | - private int serverPort; | |
| 87 | - | |
| 88 | - | |
| 89 | - @Autowired | |
| 90 | - private IRedisCatchStorage redisCatchStorage; | |
| 91 | - | |
| 92 | - | |
| 93 | 79 | @GetMapping(value = "/receive/open") |
| 94 | 80 | @ResponseBody |
| 95 | 81 | @Operation(summary = "开启收流和获取发流信息") |
| ... | ... | @@ -121,12 +107,16 @@ public class RtpController { |
| 121 | 107 | }catch (NumberFormatException e) { |
| 122 | 108 | throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误"); |
| 123 | 109 | } |
| 124 | - | |
| 125 | 110 | } |
| 126 | - int localPort = zlmServerFactory.createRTPServer(mediaServerItem, stream, ssrcInt, null, false, tcpMode); | |
| 111 | + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + callId + "_" + stream; | |
| 112 | + int localPortForVideo = zlmServerFactory.createRTPServer(mediaServerItem, stream, ssrcInt, null, false, tcpMode); | |
| 113 | + int localPortForAudio = zlmServerFactory.createRTPServer(mediaServerItem, stream + "_a" , ssrcInt, null, false, tcpMode); | |
| 114 | + if (localPortForVideo == 0 || localPortForAudio == 0) { | |
| 115 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败"); | |
| 116 | + } | |
| 127 | 117 | // 注册回调如果rtp收流超时则通过回调发送通知 |
| 128 | 118 | if (callBack != null) { |
| 129 | - HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, mediaServerItem.getId()); | |
| 119 | + HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(stream, String.valueOf(ssrcInt), mediaServerItem.getId()); | |
| 130 | 120 | // 订阅 zlm启动事件, 新的zlm也会从这里进入系统 |
| 131 | 121 | hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout, |
| 132 | 122 | (mediaServerItemInUse, hookParam)->{ |
| ... | ... | @@ -140,22 +130,33 @@ public class RtpController { |
| 140 | 130 | try { |
| 141 | 131 | client.newCall(request).execute(); |
| 142 | 132 | } catch (IOException e) { |
| 143 | - logger.error("[开启收流和获取发流信息] 等待收流超时 callId->{}, 发送回调失败", callId, e); | |
| 133 | + logger.error("[第三方服务对接->开启收流和获取发流信息] 等待收流超时 callId->{}, 发送回调失败", callId, e); | |
| 144 | 134 | } |
| 135 | + hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout); | |
| 145 | 136 | } |
| 146 | 137 | }); |
| 147 | 138 | } |
| 148 | 139 | String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + callId; |
| 149 | 140 | OtherRtpSendInfo otherRtpSendInfo = new OtherRtpSendInfo(); |
| 150 | 141 | otherRtpSendInfo.setReceiveIp(mediaServerItem.getSdpIp()); |
| 151 | - otherRtpSendInfo.setReceivePort(localPort); | |
| 142 | + otherRtpSendInfo.setReceivePortForVideo(localPortForVideo); | |
| 143 | + otherRtpSendInfo.setReceivePortForAudio(localPortForAudio); | |
| 152 | 144 | otherRtpSendInfo.setCallId(callId); |
| 153 | 145 | otherRtpSendInfo.setStream(stream); |
| 146 | + | |
| 147 | + // 将信息写入redis中,以备后用 | |
| 148 | + redisTemplate.opsForValue().set(receiveKey, otherRtpSendInfo); | |
| 154 | 149 | if (isSend != null && isSend) { |
| 155 | - int port = sendRtpPortManager.getNextPort(mediaServerItem.getId()); | |
| 156 | - otherRtpSendInfo.setIp(mediaServerItem.getSdpIp()); | |
| 157 | - otherRtpSendInfo.setPort(port); | |
| 158 | - logger.info("[开启收流和获取发流信息] 结果,callId->{}, {}", callId, otherRtpSendInfo); | |
| 150 | + String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + "_" + callId; | |
| 151 | + // 预创建发流信息 | |
| 152 | + int portForVideo = sendRtpPortManager.getNextPort(mediaServerItem.getId()); | |
| 153 | + int portForAudio = sendRtpPortManager.getNextPort(mediaServerItem.getId()); | |
| 154 | + // 将信息写入redis中,以备后用 | |
| 155 | + redisTemplate.opsForValue().set(key, otherRtpSendInfo, 300, TimeUnit.SECONDS); | |
| 156 | + otherRtpSendInfo.setSendLocalIp(mediaServerItem.getSdpIp()); | |
| 157 | + otherRtpSendInfo.setSendLocalPortForVideo(portForVideo); | |
| 158 | + otherRtpSendInfo.setSendLocalPortForAudio(portForAudio); | |
| 159 | + logger.info("[第三方服务对接->开启收流和获取发流信息] 结果,callId->{}, {}", callId, otherRtpSendInfo); | |
| 159 | 160 | } |
| 160 | 161 | // 将信息写入redis中,以备后用 |
| 161 | 162 | redisTemplate.opsForValue().set(key, otherRtpSendInfo, 300, TimeUnit.SECONDS); |
| ... | ... | @@ -170,28 +171,69 @@ public class RtpController { |
| 170 | 171 | logger.info("[第三方服务对接->关闭收流] stream->{}", stream); |
| 171 | 172 | MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer(); |
| 172 | 173 | zlmServerFactory.closeRtpServer(mediaServerItem,stream); |
| 174 | + zlmServerFactory.closeRtpServer(mediaServerItem,stream + "_a"); | |
| 175 | + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_*_" + stream; | |
| 176 | + List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey); | |
| 177 | + if (scan.size() > 0) { | |
| 178 | + for (Object key : scan) { | |
| 179 | + // 将信息写入redis中,以备后用 | |
| 180 | + redisTemplate.delete(key); | |
| 181 | + } | |
| 182 | + } | |
| 173 | 183 | } |
| 174 | 184 | |
| 175 | 185 | @GetMapping(value = "/send/start") |
| 176 | 186 | @ResponseBody |
| 177 | 187 | @Operation(summary = "发送流") |
| 178 | 188 | @Parameter(name = "ssrc", description = "发送流的SSRC", required = true) |
| 179 | - @Parameter(name = "ip", description = "目标IP", required = true) | |
| 180 | - @Parameter(name = "port", description = "目标端口", required = true) | |
| 189 | + @Parameter(name = "dstIpForAudio", description = "目标音频收流IP", required = false) | |
| 190 | + @Parameter(name = "dstIpForVideo", description = "目标视频收流IP", required = false) | |
| 191 | + @Parameter(name = "dstPortForAudio", description = "目标音频收流端口", required = false) | |
| 192 | + @Parameter(name = "dstPortForVideo", description = "目标视频收流端口", required = false) | |
| 181 | 193 | @Parameter(name = "app", description = "待发送应用名", required = true) |
| 182 | 194 | @Parameter(name = "stream", description = "待发送流Id", required = true) |
| 183 | 195 | @Parameter(name = "callId", description = "整个过程的唯一标识,不传则使用随机端口发流", required = true) |
| 184 | - @Parameter(name = "onlyAudio", description = "是否只有音频", required = true) | |
| 185 | 196 | @Parameter(name = "isUdp", description = "是否为UDP", required = true) |
| 186 | - @Parameter(name = "streamType", description = "流类型,1为es流,2为ps流, 默认es流", required = false) | |
| 187 | - public void sendRTP(String ssrc, String ip, Integer port, String app, String stream, String callId, Boolean onlyAudio, Boolean isUdp, @RequestParam(required = false)Integer streamType) { | |
| 188 | - logger.info("[第三方服务对接->发送流] ssrc->{}, ip->{}, port->{}, app->{}, stream->{}, callId->{}, onlyAudio->{}, streamType->{}", | |
| 189 | - ssrc, ip, port, app, stream, callId, onlyAudio, streamType == 1? "ES":"PS"); | |
| 190 | - if (ObjectUtils.isEmpty(streamType)) { | |
| 191 | - streamType = 1; | |
| 197 | + @Parameter(name = "ptForAudio", description = "rtp的音频pt", required = false) | |
| 198 | + @Parameter(name = "ptForVideo", description = "rtp的视频pt", required = false) | |
| 199 | + public void sendRTP(String ssrc, | |
| 200 | + @RequestParam(required = false)String dstIpForAudio, | |
| 201 | + @RequestParam(required = false)String dstIpForVideo, | |
| 202 | + @RequestParam(required = false)Integer dstPortForAudio, | |
| 203 | + @RequestParam(required = false)Integer dstPortForVideo, | |
| 204 | + String app, | |
| 205 | + String stream, | |
| 206 | + String callId, | |
| 207 | + Boolean isUdp, | |
| 208 | + @RequestParam(required = false)Integer ptForAudio, | |
| 209 | + @RequestParam(required = false)Integer ptForVideo | |
| 210 | + ) { | |
| 211 | + logger.info("[第三方服务对接->发送流] " + | |
| 212 | + "ssrc->{}, \r\n" + | |
| 213 | + "dstIpForAudio->{}, \n" + | |
| 214 | + "dstIpForAudio->{}, \n" + | |
| 215 | + "dstPortForAudio->{}, \n" + | |
| 216 | + "dstPortForVideo->{}, \n" + | |
| 217 | + "app->{}, \n" + | |
| 218 | + "stream->{}, \n" + | |
| 219 | + "callId->{}, \n" + | |
| 220 | + "ptForAudio->{}, \n" + | |
| 221 | + "ptForVideo->{}", | |
| 222 | + ssrc, | |
| 223 | + dstIpForAudio, | |
| 224 | + dstIpForVideo, | |
| 225 | + dstPortForAudio, | |
| 226 | + dstPortForVideo, | |
| 227 | + app, | |
| 228 | + stream, | |
| 229 | + callId, | |
| 230 | + ptForAudio, | |
| 231 | + ptForVideo); | |
| 232 | + if (!((dstPortForAudio > 0 && !ObjectUtils.isEmpty(dstPortForAudio) || (dstPortForVideo > 0 && !ObjectUtils.isEmpty(dstIpForVideo))))) { | |
| 233 | + throw new ControllerException(ErrorCode.ERROR400.getCode(), "至少应该存在一组音频或视频发送参数"); | |
| 192 | 234 | } |
| 193 | 235 | MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer(); |
| 194 | - String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + callId; | |
| 236 | + String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + "_" + callId; | |
| 195 | 237 | OtherRtpSendInfo sendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key); |
| 196 | 238 | if (sendInfo == null) { |
| 197 | 239 | sendInfo = new OtherRtpSendInfo(); |
| ... | ... | @@ -200,32 +242,123 @@ public class RtpController { |
| 200 | 242 | sendInfo.setPushStream(stream); |
| 201 | 243 | sendInfo.setPushSSRC(ssrc); |
| 202 | 244 | |
| 203 | - Map<String, Object> param = new HashMap<>(12); | |
| 204 | - param.put("vhost","__defaultVhost__"); | |
| 205 | - param.put("app",app); | |
| 206 | - param.put("stream",stream); | |
| 207 | - param.put("ssrc", ssrc); | |
| 245 | + Map<String, Object> paramForAudio; | |
| 246 | + Map<String, Object> paramForVideo; | |
| 247 | + if (!ObjectUtils.isEmpty(dstIpForAudio) && dstPortForAudio > 0) { | |
| 248 | + paramForAudio = new HashMap<>(); | |
| 249 | + paramForAudio.put("vhost","__defaultVhost__"); | |
| 250 | + paramForAudio.put("app",app); | |
| 251 | + paramForAudio.put("stream",stream); | |
| 252 | + paramForAudio.put("ssrc", ssrc); | |
| 253 | + | |
| 254 | + paramForAudio.put("dst_url", dstIpForAudio); | |
| 255 | + paramForAudio.put("dst_port", dstPortForAudio); | |
| 256 | + String is_Udp = isUdp ? "1" : "0"; | |
| 257 | + paramForAudio.put("is_udp", is_Udp); | |
| 258 | + paramForAudio.put("src_port", sendInfo.getSendLocalPortForAudio()); | |
| 259 | + paramForAudio.put("use_ps", "0"); | |
| 260 | + paramForAudio.put("only_audio", "1"); | |
| 261 | + if (ptForAudio != null) { | |
| 262 | + paramForAudio.put("pt", ptForAudio); | |
| 263 | + } | |
| 208 | 264 | |
| 209 | - param.put("dst_url",ip); | |
| 210 | - param.put("dst_port", port); | |
| 211 | - String is_Udp = isUdp ? "1" : "0"; | |
| 212 | - param.put("is_udp", is_Udp); | |
| 213 | - param.put("src_port", sendInfo.getPort()); | |
| 214 | - param.put("use_ps", streamType==2 ? "1" : "0"); | |
| 215 | - param.put("only_audio", onlyAudio ? "1" : "0"); | |
| 265 | + } else { | |
| 266 | + paramForAudio = null; | |
| 267 | + } | |
| 268 | + if (!ObjectUtils.isEmpty(dstIpForVideo) && dstPortForVideo > 0) { | |
| 269 | + paramForVideo = new HashMap<>(); | |
| 270 | + paramForVideo.put("vhost","__defaultVhost__"); | |
| 271 | + paramForVideo.put("app",app); | |
| 272 | + paramForVideo.put("stream",stream); | |
| 273 | + paramForVideo.put("ssrc", ssrc); | |
| 274 | + | |
| 275 | + paramForVideo.put("dst_url", dstIpForVideo); | |
| 276 | + paramForVideo.put("dst_port", dstPortForVideo); | |
| 277 | + String is_Udp = isUdp ? "1" : "0"; | |
| 278 | + paramForVideo.put("is_udp", is_Udp); | |
| 279 | + paramForVideo.put("src_port", sendInfo.getSendLocalPortForVideo()); | |
| 280 | + paramForVideo.put("use_ps", "0"); | |
| 281 | + paramForVideo.put("only_audio", "0"); | |
| 282 | + if (ptForVideo != null) { | |
| 283 | + paramForVideo.put("pt", ptForVideo); | |
| 284 | + } | |
| 216 | 285 | |
| 217 | - JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, param); | |
| 218 | - if (jsonObject.getInteger("code") == 0) { | |
| 219 | - logger.info("[第三方服务对接->发送流] 发流成功,callId->{}", callId); | |
| 220 | - redisTemplate.opsForValue().set(key, sendInfo); | |
| 221 | - }else { | |
| 222 | - redisTemplate.delete(key); | |
| 223 | - logger.info("[第三方服务对接->发送流] 发流失败,callId->{}, {}", callId, jsonObject.getString("msg")); | |
| 224 | - throw new ControllerException(ErrorCode.ERROR100.getCode(), "[发流失败] " + jsonObject.getString("msg")); | |
| 286 | + } else { | |
| 287 | + paramForVideo = null; | |
| 225 | 288 | } |
| 226 | - } | |
| 227 | 289 | |
| 290 | + Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream); | |
| 291 | + if (streamReady) { | |
| 292 | + if (paramForVideo != null) { | |
| 293 | + JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, paramForVideo); | |
| 294 | + if (jsonObject.getInteger("code") == 0) { | |
| 295 | + logger.info("[第三方服务对接->发送流] 视频流发流成功,callId->{},param->{}", callId, paramForVideo); | |
| 296 | + redisTemplate.opsForValue().set(key, sendInfo); | |
| 297 | + }else { | |
| 298 | + redisTemplate.delete(key); | |
| 299 | + logger.info("[第三方服务对接->发送流] 视频流发流失败,callId->{}, {}", callId, jsonObject.getString("msg")); | |
| 300 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "[视频流发流失败] " + jsonObject.getString("msg")); | |
| 301 | + } | |
| 302 | + } | |
| 303 | + if(paramForAudio != null) { | |
| 304 | + JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, paramForAudio); | |
| 305 | + if (jsonObject.getInteger("code") == 0) { | |
| 306 | + logger.info("[第三方服务对接->发送流] 音频流发流成功,callId->{},param->{}", callId, paramForAudio); | |
| 307 | + redisTemplate.opsForValue().set(key, sendInfo); | |
| 308 | + }else { | |
| 309 | + redisTemplate.delete(key); | |
| 310 | + logger.info("[第三方服务对接->发送流] 音频流发流失败,callId->{}, {}", callId, jsonObject.getString("msg")); | |
| 311 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "[音频流发流失败] " + jsonObject.getString("msg")); | |
| 312 | + } | |
| 313 | + } | |
| 314 | + }else { | |
| 315 | + logger.info("[第三方服务对接->发送流] 流不存在,等待流上线,callId->{}", callId); | |
| 316 | + String uuid = UUID.randomUUID().toString(); | |
| 317 | + HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed(app, stream, true, "rtsp", mediaServerItem.getId()); | |
| 318 | + dynamicTask.startDelay(uuid, ()->{ | |
| 319 | + logger.info("[第三方服务对接->发送流] 等待流上线超时 callId->{}", callId); | |
| 320 | + redisTemplate.delete(key); | |
| 321 | + hookSubscribe.removeSubscribe(hookSubscribeForStreamChange); | |
| 322 | + }, 10000); | |
| 228 | 323 | |
| 324 | + // 订阅 zlm启动事件, 新的zlm也会从这里进入系统 | |
| 325 | + OtherRtpSendInfo finalSendInfo = sendInfo; | |
| 326 | + hookSubscribe.removeSubscribe(hookSubscribeForStreamChange); | |
| 327 | + hookSubscribe.addSubscribe(hookSubscribeForStreamChange, | |
| 328 | + (mediaServerItemInUse, response)->{ | |
| 329 | + dynamicTask.stop(uuid); | |
| 330 | + logger.info("[第三方服务对接->发送流] 流上线,开始发流 callId->{}", callId); | |
| 331 | + try { | |
| 332 | + Thread.sleep(400); | |
| 333 | + } catch (InterruptedException e) { | |
| 334 | + throw new RuntimeException(e); | |
| 335 | + } | |
| 336 | + if (paramForVideo != null) { | |
| 337 | + JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, paramForVideo); | |
| 338 | + if (jsonObject.getInteger("code") == 0) { | |
| 339 | + logger.info("[第三方服务对接->发送流] 视频流发流成功,callId->{},param->{}", callId, paramForVideo); | |
| 340 | + redisTemplate.opsForValue().set(key, finalSendInfo); | |
| 341 | + }else { | |
| 342 | + redisTemplate.delete(key); | |
| 343 | + logger.info("[第三方服务对接->发送流] 视频流发流失败,callId->{}, {}", callId, jsonObject.getString("msg")); | |
| 344 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "[视频流发流失败] " + jsonObject.getString("msg")); | |
| 345 | + } | |
| 346 | + } | |
| 347 | + if(paramForAudio != null) { | |
| 348 | + JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, paramForAudio); | |
| 349 | + if (jsonObject.getInteger("code") == 0) { | |
| 350 | + logger.info("[第三方服务对接->发送流] 音频流发流成功,callId->{},param->{}", callId, paramForAudio); | |
| 351 | + redisTemplate.opsForValue().set(key, finalSendInfo); | |
| 352 | + }else { | |
| 353 | + redisTemplate.delete(key); | |
| 354 | + logger.info("[第三方服务对接->发送流] 音频流发流失败,callId->{}, {}", callId, jsonObject.getString("msg")); | |
| 355 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "[音频流发流失败] " + jsonObject.getString("msg")); | |
| 356 | + } | |
| 357 | + } | |
| 358 | + hookSubscribe.removeSubscribe(hookSubscribeForStreamChange); | |
| 359 | + }); | |
| 360 | + } | |
| 361 | + } | |
| 229 | 362 | |
| 230 | 363 | @GetMapping(value = "/send/stop") |
| 231 | 364 | @ResponseBody |
| ... | ... | @@ -233,7 +366,7 @@ public class RtpController { |
| 233 | 366 | @Parameter(name = "callId", description = "整个过程的唯一标识,不传则使用随机端口发流", required = true) |
| 234 | 367 | public void closeSendRTP(String callId) { |
| 235 | 368 | logger.info("[第三方服务对接->关闭发送流] callId->{}", callId); |
| 236 | - String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + callId; | |
| 369 | + String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + "_" + callId; | |
| 237 | 370 | OtherRtpSendInfo sendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key); |
| 238 | 371 | if (sendInfo == null){ |
| 239 | 372 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "未开启发流"); |
| ... | ... | @@ -251,6 +384,7 @@ public class RtpController { |
| 251 | 384 | }else { |
| 252 | 385 | logger.info("[第三方服务对接->关闭发送流] 成功 callId->{}", callId); |
| 253 | 386 | } |
| 387 | + redisTemplate.delete(key); | |
| 254 | 388 | } |
| 255 | 389 | |
| 256 | 390 | } | ... | ... |