Commit 885842249fb6b264b0abf78668872d04bdc179ce
1 parent
0a3d25fb
优化第三方对接接口
Showing
3 changed files
with
82 additions
and
22 deletions
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| @@ -154,6 +154,7 @@ public class VideoManagerConstants { | @@ -154,6 +154,7 @@ public class VideoManagerConstants { | ||
| 154 | public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; | 154 | public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; |
| 155 | public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; | 155 | public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; |
| 156 | public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_"; | 156 | public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_"; |
| 157 | + public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_"; | ||
| 157 | 158 | ||
| 158 | /** | 159 | /** |
| 159 | * Redis Const | 160 | * Redis Const |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.zlm; | @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.zlm; | ||
| 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; | 5 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 6 | +import com.genersoft.iot.vmp.common.VideoManagerConstants; | ||
| 6 | import com.genersoft.iot.vmp.conf.UserSetting; | 7 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 7 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | 8 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; |
| 8 | import com.genersoft.iot.vmp.gb28181.bean.*; | 9 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| @@ -22,14 +23,13 @@ import com.genersoft.iot.vmp.service.*; | @@ -22,14 +23,13 @@ import com.genersoft.iot.vmp.service.*; | ||
| 22 | import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; | 23 | import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; |
| 23 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | 24 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 24 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | 25 | 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.StreamContent; | ||
| 28 | -import com.genersoft.iot.vmp.vmanager.bean.WVPResult; | 26 | +import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
| 27 | +import com.genersoft.iot.vmp.vmanager.bean.*; | ||
| 29 | import org.slf4j.Logger; | 28 | import org.slf4j.Logger; |
| 30 | import org.slf4j.LoggerFactory; | 29 | import org.slf4j.LoggerFactory; |
| 31 | import org.springframework.beans.factory.annotation.Autowired; | 30 | import org.springframework.beans.factory.annotation.Autowired; |
| 32 | import org.springframework.beans.factory.annotation.Qualifier; | 31 | import org.springframework.beans.factory.annotation.Qualifier; |
| 32 | +import org.springframework.data.redis.core.RedisTemplate; | ||
| 33 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | 33 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| 34 | import org.springframework.util.ObjectUtils; | 34 | import org.springframework.util.ObjectUtils; |
| 35 | import org.springframework.web.bind.annotation.*; | 35 | import org.springframework.web.bind.annotation.*; |
| @@ -106,6 +106,9 @@ public class ZLMHttpHookListener { | @@ -106,6 +106,9 @@ public class ZLMHttpHookListener { | ||
| 106 | @Autowired | 106 | @Autowired |
| 107 | private AssistRESTfulUtils assistRESTfulUtils; | 107 | private AssistRESTfulUtils assistRESTfulUtils; |
| 108 | 108 | ||
| 109 | + @Autowired | ||
| 110 | + private RedisTemplate<Object, Object> redisTemplate; | ||
| 111 | + | ||
| 109 | @Qualifier("taskExecutor") | 112 | @Qualifier("taskExecutor") |
| 110 | @Autowired | 113 | @Autowired |
| 111 | private ThreadPoolTaskExecutor taskExecutor; | 114 | private ThreadPoolTaskExecutor taskExecutor; |
| @@ -255,6 +258,21 @@ public class ZLMHttpHookListener { | @@ -255,6 +258,21 @@ public class ZLMHttpHookListener { | ||
| 255 | result.setEnable_mp4(true); | 258 | result.setEnable_mp4(true); |
| 256 | } | 259 | } |
| 257 | } | 260 | } |
| 261 | + | ||
| 262 | + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "*"; | ||
| 263 | + // 将信息写入redis中,以备后用 | ||
| 264 | + List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey); | ||
| 265 | + if (scan.size()>0) { | ||
| 266 | + for (Object o : scan) { | ||
| 267 | + String key = (String) o; | ||
| 268 | + OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key); | ||
| 269 | + if (otherRtpSendInfo != null && otherRtpSendInfo.getStream().equalsIgnoreCase(param.getStream())) { | ||
| 270 | + result.setEnable_audio(true); | ||
| 271 | + result.setEnable_mp4(true); | ||
| 272 | + } | ||
| 273 | + } | ||
| 274 | + } | ||
| 275 | + | ||
| 258 | if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { | 276 | if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { |
| 259 | logger.info("推流时发现尚未设置录像路径,从assist服务中读取"); | 277 | logger.info("推流时发现尚未设置录像路径,从assist服务中读取"); |
| 260 | JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null); | 278 | JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null); |
src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java
| @@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; | @@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; | ||
| 11 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | 11 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| 12 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | 12 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 13 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; | 13 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; |
| 14 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | ||
| 14 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 15 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 15 | import com.genersoft.iot.vmp.service.IDeviceChannelService; | 16 | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| 16 | import com.genersoft.iot.vmp.service.IDeviceService; | 17 | import com.genersoft.iot.vmp.service.IDeviceService; |
| @@ -34,6 +35,7 @@ import org.springframework.web.bind.annotation.*; | @@ -34,6 +35,7 @@ import org.springframework.web.bind.annotation.*; | ||
| 34 | import java.io.IOException; | 35 | import java.io.IOException; |
| 35 | import java.util.HashMap; | 36 | import java.util.HashMap; |
| 36 | import java.util.Map; | 37 | import java.util.Map; |
| 38 | +import java.util.UUID; | ||
| 37 | 39 | ||
| 38 | @SuppressWarnings("rawtypes") | 40 | @SuppressWarnings("rawtypes") |
| 39 | @Tag(name = "第三方服务对接") | 41 | @Tag(name = "第三方服务对接") |
| @@ -120,12 +122,12 @@ public class RtpController { | @@ -120,12 +122,12 @@ public class RtpController { | ||
| 120 | int localPort = zlmServerFactory.createRTPServer(mediaServerItem, stream, ssrcInt, null, false, tcpMode); | 122 | int localPort = zlmServerFactory.createRTPServer(mediaServerItem, stream, ssrcInt, null, false, tcpMode); |
| 121 | // 注册回调如果rtp收流超时则通过回调发送通知 | 123 | // 注册回调如果rtp收流超时则通过回调发送通知 |
| 122 | if (callBack != null) { | 124 | if (callBack != null) { |
| 123 | - HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, mediaServerItem.getId()); | 125 | + HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(stream, String.valueOf(ssrcInt), mediaServerItem.getId()); |
| 124 | // 订阅 zlm启动事件, 新的zlm也会从这里进入系统 | 126 | // 订阅 zlm启动事件, 新的zlm也会从这里进入系统 |
| 125 | hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout, | 127 | hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout, |
| 126 | (mediaServerItemInUse, response)->{ | 128 | (mediaServerItemInUse, response)->{ |
| 127 | if (stream.equals(response.getString("stream_id"))) { | 129 | if (stream.equals(response.getString("stream_id"))) { |
| 128 | - logger.info("[开启收流和获取发流信息] 等待收流超时 callId->{}, 发送回调", callId); | 130 | + logger.info("[第三方服务对接->开启收流和获取发流信息] 等待收流超时 callId->{}, 发送回调", callId); |
| 129 | OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); | 131 | OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); |
| 130 | OkHttpClient client = httpClientBuilder.build(); | 132 | OkHttpClient client = httpClientBuilder.build(); |
| 131 | String url = callBack + "?callId=" + callId; | 133 | String url = callBack + "?callId=" + callId; |
| @@ -133,7 +135,7 @@ public class RtpController { | @@ -133,7 +135,7 @@ public class RtpController { | ||
| 133 | try { | 135 | try { |
| 134 | client.newCall(request).execute(); | 136 | client.newCall(request).execute(); |
| 135 | } catch (IOException e) { | 137 | } catch (IOException e) { |
| 136 | - logger.error("[开启收流和获取发流信息] 等待收流超时 callId->{}, 发送回调失败", callId, e); | 138 | + logger.error("[第三方服务对接->开启收流和获取发流信息] 等待收流超时 callId->{}, 发送回调失败", callId, e); |
| 137 | } | 139 | } |
| 138 | } | 140 | } |
| 139 | }); | 141 | }); |
| @@ -143,6 +145,9 @@ public class RtpController { | @@ -143,6 +145,9 @@ public class RtpController { | ||
| 143 | otherRtpSendInfo.setReceivePort(localPort); | 145 | otherRtpSendInfo.setReceivePort(localPort); |
| 144 | otherRtpSendInfo.setCallId(callId); | 146 | otherRtpSendInfo.setCallId(callId); |
| 145 | otherRtpSendInfo.setStream(stream); | 147 | otherRtpSendInfo.setStream(stream); |
| 148 | + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + stream; | ||
| 149 | + // 将信息写入redis中,以备后用 | ||
| 150 | + redisTemplate.opsForValue().set(receiveKey, otherRtpSendInfo); | ||
| 146 | if (isSend != null && isSend) { | 151 | if (isSend != null && isSend) { |
| 147 | String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + callId; | 152 | String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + callId; |
| 148 | // 预创建发流信息 | 153 | // 预创建发流信息 |
| @@ -160,7 +165,7 @@ public class RtpController { | @@ -160,7 +165,7 @@ public class RtpController { | ||
| 160 | }, 15000); | 165 | }, 15000); |
| 161 | otherRtpSendInfo.setIp(mediaServerItem.getSdpIp()); | 166 | otherRtpSendInfo.setIp(mediaServerItem.getSdpIp()); |
| 162 | otherRtpSendInfo.setPort(port); | 167 | otherRtpSendInfo.setPort(port); |
| 163 | - logger.info("[开启收流和获取发流信息] 结果,callId->{}, {}", callId, otherRtpSendInfo); | 168 | + logger.info("[第三方服务对接->开启收流和获取发流信息] 结果,callId->{}, {}", callId, otherRtpSendInfo); |
| 164 | } | 169 | } |
| 165 | return otherRtpSendInfo; | 170 | return otherRtpSendInfo; |
| 166 | } | 171 | } |
| @@ -173,6 +178,9 @@ public class RtpController { | @@ -173,6 +178,9 @@ public class RtpController { | ||
| 173 | logger.info("[第三方服务对接->关闭收流] stream->{}", stream); | 178 | logger.info("[第三方服务对接->关闭收流] stream->{}", stream); |
| 174 | MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer(); | 179 | MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer(); |
| 175 | zlmServerFactory.closeRtpServer(mediaServerItem,stream); | 180 | zlmServerFactory.closeRtpServer(mediaServerItem,stream); |
| 181 | + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + stream; | ||
| 182 | + // 将信息写入redis中,以备后用 | ||
| 183 | + redisTemplate.delete(receiveKey); | ||
| 176 | } | 184 | } |
| 177 | 185 | ||
| 178 | @GetMapping(value = "/send/start") | 186 | @GetMapping(value = "/send/start") |
| @@ -187,9 +195,10 @@ public class RtpController { | @@ -187,9 +195,10 @@ public class RtpController { | ||
| 187 | @Parameter(name = "onlyAudio", description = "是否只有音频", required = true) | 195 | @Parameter(name = "onlyAudio", description = "是否只有音频", required = true) |
| 188 | @Parameter(name = "isUdp", description = "是否为UDP", required = true) | 196 | @Parameter(name = "isUdp", description = "是否为UDP", required = true) |
| 189 | @Parameter(name = "streamType", description = "流类型,1为es流,2为ps流, 默认es流", required = false) | 197 | @Parameter(name = "streamType", description = "流类型,1为es流,2为ps流, 默认es流", required = false) |
| 190 | - public void sendRTP(String ssrc, String ip, Integer port, String app, String stream, String callId, Boolean onlyAudio, Boolean isUdp, @RequestParam(required = false)Integer streamType) { | ||
| 191 | - logger.info("[第三方服务对接->发送流] ssrc->{}, ip->{}, port->{}, app->{}, stream->{}, callId->{}, onlyAudio->{}, streamType->{}", | ||
| 192 | - ssrc, ip, port, app, stream, callId, onlyAudio, streamType == 1? "ES":"PS"); | 198 | + @Parameter(name = "pt", description = "rtp的pt", required = true) |
| 199 | + public void sendRTP(String ssrc, String ip, Integer port, String app, String stream, String callId, Boolean onlyAudio, Boolean isUdp, @RequestParam(required = false)Integer streamType, Integer pt) { | ||
| 200 | + logger.info("[第三方服务对接->发送流] ssrc->{}, ip->{}, port->{}, app->{}, stream->{}, callId->{}, onlyAudio->{}, streamType->{}, pt->{}", | ||
| 201 | + ssrc, ip, port, app, stream, callId, onlyAudio, streamType == 1? "ES":"PS", pt); | ||
| 193 | if (ObjectUtils.isEmpty(streamType)) { | 202 | if (ObjectUtils.isEmpty(streamType)) { |
| 194 | streamType = 1; | 203 | streamType = 1; |
| 195 | } | 204 | } |
| @@ -197,7 +206,7 @@ public class RtpController { | @@ -197,7 +206,7 @@ public class RtpController { | ||
| 197 | String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + callId; | 206 | String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + callId; |
| 198 | OtherRtpSendInfo sendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key); | 207 | OtherRtpSendInfo sendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key); |
| 199 | if (sendInfo != null) { | 208 | if (sendInfo != null) { |
| 200 | - zlmServerFactory.releasePort(mediaServerItem, sendInfo.getCallId()); | 209 | + zlmServerFactory.releasePort(mediaServerItem, callId); |
| 201 | }else { | 210 | }else { |
| 202 | sendInfo = new OtherRtpSendInfo(); | 211 | sendInfo = new OtherRtpSendInfo(); |
| 203 | } | 212 | } |
| @@ -218,20 +227,52 @@ public class RtpController { | @@ -218,20 +227,52 @@ public class RtpController { | ||
| 218 | param.put("src_port", sendInfo.getPort()); | 227 | param.put("src_port", sendInfo.getPort()); |
| 219 | param.put("use_ps", streamType==2 ? "1" : "0"); | 228 | param.put("use_ps", streamType==2 ? "1" : "0"); |
| 220 | param.put("only_audio", onlyAudio ? "1" : "0"); | 229 | param.put("only_audio", onlyAudio ? "1" : "0"); |
| 221 | - | ||
| 222 | - JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, param); | ||
| 223 | - if (jsonObject.getInteger("code") == 0) { | ||
| 224 | - logger.info("[第三方服务对接->发送流] 发流成功,callId->{}", callId); | ||
| 225 | - redisTemplate.opsForValue().set(key, sendInfo); | 230 | + param.put("pt", pt); |
| 231 | + | ||
| 232 | + dynamicTask.stop(key); | ||
| 233 | + Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream); | ||
| 234 | + if (streamReady) { | ||
| 235 | + logger.info("[第三方服务对接->发送流] 流存在,开始发流,callId->{}", callId); | ||
| 236 | + JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, param); | ||
| 237 | + if (jsonObject.getInteger("code") == 0) { | ||
| 238 | + logger.info("[第三方服务对接->发送流] 发流成功,callId->{}", callId); | ||
| 239 | + redisTemplate.opsForValue().set(key, sendInfo); | ||
| 240 | + }else { | ||
| 241 | + redisTemplate.delete(key); | ||
| 242 | + logger.info("[第三方服务对接->发送流] 发流失败,callId->{}, {}", callId, jsonObject.getString("msg")); | ||
| 243 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "[发流失败] " + jsonObject.getString("msg")); | ||
| 244 | + } | ||
| 226 | }else { | 245 | }else { |
| 227 | - redisTemplate.delete(key); | ||
| 228 | - logger.info("[第三方服务对接->发送流] 发流失败,callId->{}, {}", callId, jsonObject.getString("msg")); | ||
| 229 | - throw new ControllerException(ErrorCode.ERROR100.getCode(), "[发流失败] " + jsonObject.getString("msg")); | 246 | + logger.info("[第三方服务对接->发送流] 流不存在,等待流上线,callId->{}", callId); |
| 247 | + String uuid = UUID.randomUUID().toString(); | ||
| 248 | + HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed(app, stream, true, "rtsp", mediaServerItem.getId()); | ||
| 249 | + dynamicTask.startDelay(uuid, ()->{ | ||
| 250 | + logger.info("[第三方服务对接->发送流] 等待流上线超时 callId->{}", callId); | ||
| 251 | + redisTemplate.delete(key); | ||
| 252 | + hookSubscribe.removeSubscribe(hookSubscribeForStreamChange); | ||
| 253 | + }, 10000); | ||
| 254 | + | ||
| 255 | + // 订阅 zlm启动事件, 新的zlm也会从这里进入系统 | ||
| 256 | + OtherRtpSendInfo finalSendInfo = sendInfo; | ||
| 257 | + hookSubscribe.addSubscribe(hookSubscribeForStreamChange, | ||
| 258 | + (mediaServerItemInUse, response)->{ | ||
| 259 | + dynamicTask.stop(uuid); | ||
| 260 | + logger.info("[第三方服务对接->发送流] 流上线,开始发流 callId->{}", callId); | ||
| 261 | + JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, param); | ||
| 262 | + System.out.println("========发流结果=========="); | ||
| 263 | + System.out.println(jsonObject); | ||
| 264 | + if (jsonObject.getInteger("code") == 0) { | ||
| 265 | + logger.info("[第三方服务对接->发送流] 发流成功,callId->{}", callId); | ||
| 266 | + redisTemplate.opsForValue().set(key, finalSendInfo); | ||
| 267 | + }else { | ||
| 268 | + redisTemplate.delete(key); | ||
| 269 | + logger.info("[第三方服务对接->发送流] 发流失败,callId->{}, {}", callId, jsonObject.getString("msg")); | ||
| 270 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "[发流失败] " + jsonObject.getString("msg")); | ||
| 271 | + } | ||
| 272 | + }); | ||
| 230 | } | 273 | } |
| 231 | } | 274 | } |
| 232 | 275 | ||
| 233 | - | ||
| 234 | - | ||
| 235 | @GetMapping(value = "/send/stop") | 276 | @GetMapping(value = "/send/stop") |
| 236 | @ResponseBody | 277 | @ResponseBody |
| 237 | @Operation(summary = "关闭发送流") | 278 | @Operation(summary = "关闭发送流") |