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,6 +158,7 @@ public class VideoManagerConstants { | ||
| 158 | public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; | 158 | public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_"; |
| 159 | public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; | 159 | public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_"; |
| 160 | public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_"; | 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 | * Redis Const | 164 | * Redis Const |
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
| @@ -234,4 +234,11 @@ public class MediaConfig{ | @@ -234,4 +234,11 @@ public class MediaConfig{ | ||
| 234 | return false; | 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,7 +86,10 @@ public class ZLMServerFactory { | ||
| 86 | }else { | 86 | }else { |
| 87 | param.put("port", port); | 87 | param.put("port", port); |
| 88 | } | 88 | } |
| 89 | - param.put("ssrc", ssrc); | 89 | + if (ssrc != 0) { |
| 90 | + param.put("ssrc", ssrc); | ||
| 91 | + } | ||
| 92 | + | ||
| 90 | JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param); | 93 | JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param); |
| 91 | logger.info(JSONObject.toJSONString(openRtpServerResultJson)); | 94 | logger.info(JSONObject.toJSONString(openRtpServerResultJson)); |
| 92 | if (openRtpServerResultJson != null) { | 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,5 +51,13 @@ public class HookResultForOnPublish extends HookResult{ | ||
| 51 | this.mp4_save_path = mp4_save_path; | 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,12 +5,17 @@ public class OtherRtpSendInfo { | ||
| 5 | /** | 5 | /** |
| 6 | * 发流IP | 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 | * 收流IP | 21 | * 收流IP |
| @@ -18,9 +23,14 @@ public class OtherRtpSendInfo { | @@ -18,9 +23,14 @@ public class OtherRtpSendInfo { | ||
| 18 | private String receiveIp; | 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 | * 会话ID | 36 | * 会话ID |
| @@ -48,23 +58,6 @@ public class OtherRtpSendInfo { | @@ -48,23 +58,6 @@ public class OtherRtpSendInfo { | ||
| 48 | private String pushSSRC; | 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 | public String getReceiveIp() { | 61 | public String getReceiveIp() { |
| 69 | return receiveIp; | 62 | return receiveIp; |
| 70 | } | 63 | } |
| @@ -73,12 +66,20 @@ public class OtherRtpSendInfo { | @@ -73,12 +66,20 @@ public class OtherRtpSendInfo { | ||
| 73 | this.receiveIp = receiveIp; | 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 | public String getCallId() { | 85 | public String getCallId() { |
| @@ -121,15 +122,45 @@ public class OtherRtpSendInfo { | @@ -121,15 +122,45 @@ public class OtherRtpSendInfo { | ||
| 121 | this.pushSSRC = pushSSRC; | 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 | @Override | 150 | @Override |
| 125 | public String toString() { | 151 | public String toString() { |
| 126 | return "OtherRtpSendInfo{" + | 152 | return "OtherRtpSendInfo{" + |
| 127 | - "ip='" + ip + '\'' + | ||
| 128 | - ", port=" + port + | 153 | + "sendLocalIp='" + sendLocalIp + '\'' + |
| 154 | + ", sendLocalPortForAudio=" + sendLocalPortForAudio + | ||
| 155 | + ", sendLocalPortForVideo=" + sendLocalPortForVideo + | ||
| 129 | ", receiveIp='" + receiveIp + '\'' + | 156 | ", receiveIp='" + receiveIp + '\'' + |
| 130 | - ", receivePort=" + receivePort + | 157 | + ", receivePortForAudio=" + receivePortForAudio + |
| 158 | + ", receivePortForVideo=" + receivePortForVideo + | ||
| 131 | ", callId='" + callId + '\'' + | 159 | ", callId='" + callId + '\'' + |
| 132 | ", stream='" + stream + '\'' + | 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,21 +3,22 @@ package com.genersoft.iot.vmp.vmanager.rtp; | ||
| 3 | import com.alibaba.fastjson2.JSONObject; | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | import com.genersoft.iot.vmp.common.VideoManagerConstants; | 4 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 5 | import com.genersoft.iot.vmp.conf.DynamicTask; | 5 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 6 | -import com.genersoft.iot.vmp.conf.SipConfig; | ||
| 7 | import com.genersoft.iot.vmp.conf.UserSetting; | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 8 | -import com.genersoft.iot.vmp.conf.VersionInfo; | ||
| 9 | import com.genersoft.iot.vmp.conf.exception.ControllerException; | 7 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 10 | import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; | 8 | import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; |
| 11 | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; | 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 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | 12 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| 13 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | 13 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 14 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; | 14 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; |
| 15 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | ||
| 15 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 16 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 16 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRtpServerTimeoutHookParam; | 17 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRtpServerTimeoutHookParam; |
| 17 | import com.genersoft.iot.vmp.service.IDeviceChannelService; | 18 | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| 18 | import com.genersoft.iot.vmp.service.IDeviceService; | 19 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 19 | import com.genersoft.iot.vmp.service.IMediaServerService; | 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 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | 22 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 22 | import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; | 23 | import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; |
| 23 | import io.swagger.v3.oas.annotations.Operation; | 24 | import io.swagger.v3.oas.annotations.Operation; |
| @@ -28,14 +29,16 @@ import okhttp3.Request; | @@ -28,14 +29,16 @@ import okhttp3.Request; | ||
| 28 | import org.slf4j.Logger; | 29 | import org.slf4j.Logger; |
| 29 | import org.slf4j.LoggerFactory; | 30 | import org.slf4j.LoggerFactory; |
| 30 | import org.springframework.beans.factory.annotation.Autowired; | 31 | import org.springframework.beans.factory.annotation.Autowired; |
| 31 | -import org.springframework.beans.factory.annotation.Value; | ||
| 32 | import org.springframework.data.redis.core.RedisTemplate; | 32 | import org.springframework.data.redis.core.RedisTemplate; |
| 33 | import org.springframework.util.ObjectUtils; | 33 | import org.springframework.util.ObjectUtils; |
| 34 | import org.springframework.web.bind.annotation.*; | 34 | import org.springframework.web.bind.annotation.*; |
| 35 | 35 | ||
| 36 | import java.io.IOException; | 36 | import java.io.IOException; |
| 37 | import java.util.HashMap; | 37 | import java.util.HashMap; |
| 38 | +import java.util.List; | ||
| 38 | import java.util.Map; | 39 | import java.util.Map; |
| 40 | +import java.util.UUID; | ||
| 41 | +import java.util.concurrent.TimeUnit; | ||
| 39 | import java.util.concurrent.TimeUnit; | 42 | import java.util.concurrent.TimeUnit; |
| 40 | 43 | ||
| 41 | @SuppressWarnings("rawtypes") | 44 | @SuppressWarnings("rawtypes") |
| @@ -60,21 +63,12 @@ public class RtpController { | @@ -60,21 +63,12 @@ public class RtpController { | ||
| 60 | private IMediaServerService mediaServerService; | 63 | private IMediaServerService mediaServerService; |
| 61 | 64 | ||
| 62 | @Autowired | 65 | @Autowired |
| 63 | - private VersionInfo versionInfo; | ||
| 64 | - | ||
| 65 | - @Autowired | ||
| 66 | - private SipConfig sipConfig; | 66 | + private SendRtpPortManager sendRtpPortManager; |
| 67 | 67 | ||
| 68 | @Autowired | 68 | @Autowired |
| 69 | private UserSetting userSetting; | 69 | private UserSetting userSetting; |
| 70 | 70 | ||
| 71 | @Autowired | 71 | @Autowired |
| 72 | - private IDeviceService deviceService; | ||
| 73 | - | ||
| 74 | - @Autowired | ||
| 75 | - private IDeviceChannelService channelService; | ||
| 76 | - | ||
| 77 | - @Autowired | ||
| 78 | private DynamicTask dynamicTask; | 72 | private DynamicTask dynamicTask; |
| 79 | 73 | ||
| 80 | 74 | ||
| @@ -82,14 +76,6 @@ public class RtpController { | @@ -82,14 +76,6 @@ public class RtpController { | ||
| 82 | private RedisTemplate<Object, Object> redisTemplate; | 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 | @GetMapping(value = "/receive/open") | 79 | @GetMapping(value = "/receive/open") |
| 94 | @ResponseBody | 80 | @ResponseBody |
| 95 | @Operation(summary = "开启收流和获取发流信息") | 81 | @Operation(summary = "开启收流和获取发流信息") |
| @@ -121,12 +107,16 @@ public class RtpController { | @@ -121,12 +107,16 @@ public class RtpController { | ||
| 121 | }catch (NumberFormatException e) { | 107 | }catch (NumberFormatException e) { |
| 122 | throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误"); | 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 | // 注册回调如果rtp收流超时则通过回调发送通知 | 117 | // 注册回调如果rtp收流超时则通过回调发送通知 |
| 128 | if (callBack != null) { | 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 | // 订阅 zlm启动事件, 新的zlm也会从这里进入系统 | 120 | // 订阅 zlm启动事件, 新的zlm也会从这里进入系统 |
| 131 | hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout, | 121 | hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout, |
| 132 | (mediaServerItemInUse, hookParam)->{ | 122 | (mediaServerItemInUse, hookParam)->{ |
| @@ -140,22 +130,33 @@ public class RtpController { | @@ -140,22 +130,33 @@ public class RtpController { | ||
| 140 | try { | 130 | try { |
| 141 | client.newCall(request).execute(); | 131 | client.newCall(request).execute(); |
| 142 | } catch (IOException e) { | 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 | String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + callId; | 139 | String key = VideoManagerConstants.WVP_OTHER_SEND_RTP_INFO + userSetting.getServerId() + callId; |
| 149 | OtherRtpSendInfo otherRtpSendInfo = new OtherRtpSendInfo(); | 140 | OtherRtpSendInfo otherRtpSendInfo = new OtherRtpSendInfo(); |
| 150 | otherRtpSendInfo.setReceiveIp(mediaServerItem.getSdpIp()); | 141 | otherRtpSendInfo.setReceiveIp(mediaServerItem.getSdpIp()); |
| 151 | - otherRtpSendInfo.setReceivePort(localPort); | 142 | + otherRtpSendInfo.setReceivePortForVideo(localPortForVideo); |
| 143 | + otherRtpSendInfo.setReceivePortForAudio(localPortForAudio); | ||
| 152 | otherRtpSendInfo.setCallId(callId); | 144 | otherRtpSendInfo.setCallId(callId); |
| 153 | otherRtpSendInfo.setStream(stream); | 145 | otherRtpSendInfo.setStream(stream); |
| 146 | + | ||
| 147 | + // 将信息写入redis中,以备后用 | ||
| 148 | + redisTemplate.opsForValue().set(receiveKey, otherRtpSendInfo); | ||
| 154 | if (isSend != null && isSend) { | 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 | // 将信息写入redis中,以备后用 | 161 | // 将信息写入redis中,以备后用 |
| 161 | redisTemplate.opsForValue().set(key, otherRtpSendInfo, 300, TimeUnit.SECONDS); | 162 | redisTemplate.opsForValue().set(key, otherRtpSendInfo, 300, TimeUnit.SECONDS); |
| @@ -170,28 +171,69 @@ public class RtpController { | @@ -170,28 +171,69 @@ public class RtpController { | ||
| 170 | logger.info("[第三方服务对接->关闭收流] stream->{}", stream); | 171 | logger.info("[第三方服务对接->关闭收流] stream->{}", stream); |
| 171 | MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer(); | 172 | MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer(); |
| 172 | zlmServerFactory.closeRtpServer(mediaServerItem,stream); | 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 | @GetMapping(value = "/send/start") | 185 | @GetMapping(value = "/send/start") |
| 176 | @ResponseBody | 186 | @ResponseBody |
| 177 | @Operation(summary = "发送流") | 187 | @Operation(summary = "发送流") |
| 178 | @Parameter(name = "ssrc", description = "发送流的SSRC", required = true) | 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 | @Parameter(name = "app", description = "待发送应用名", required = true) | 193 | @Parameter(name = "app", description = "待发送应用名", required = true) |
| 182 | @Parameter(name = "stream", description = "待发送流Id", required = true) | 194 | @Parameter(name = "stream", description = "待发送流Id", required = true) |
| 183 | @Parameter(name = "callId", description = "整个过程的唯一标识,不传则使用随机端口发流", required = true) | 195 | @Parameter(name = "callId", description = "整个过程的唯一标识,不传则使用随机端口发流", required = true) |
| 184 | - @Parameter(name = "onlyAudio", description = "是否只有音频", required = true) | ||
| 185 | @Parameter(name = "isUdp", description = "是否为UDP", required = true) | 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 | MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer(); | 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 | OtherRtpSendInfo sendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key); | 237 | OtherRtpSendInfo sendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key); |
| 196 | if (sendInfo == null) { | 238 | if (sendInfo == null) { |
| 197 | sendInfo = new OtherRtpSendInfo(); | 239 | sendInfo = new OtherRtpSendInfo(); |
| @@ -200,32 +242,123 @@ public class RtpController { | @@ -200,32 +242,123 @@ public class RtpController { | ||
| 200 | sendInfo.setPushStream(stream); | 242 | sendInfo.setPushStream(stream); |
| 201 | sendInfo.setPushSSRC(ssrc); | 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 | @GetMapping(value = "/send/stop") | 363 | @GetMapping(value = "/send/stop") |
| 231 | @ResponseBody | 364 | @ResponseBody |
| @@ -233,7 +366,7 @@ public class RtpController { | @@ -233,7 +366,7 @@ public class RtpController { | ||
| 233 | @Parameter(name = "callId", description = "整个过程的唯一标识,不传则使用随机端口发流", required = true) | 366 | @Parameter(name = "callId", description = "整个过程的唯一标识,不传则使用随机端口发流", required = true) |
| 234 | public void closeSendRTP(String callId) { | 367 | public void closeSendRTP(String callId) { |
| 235 | logger.info("[第三方服务对接->关闭发送流] callId->{}", callId); | 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 | OtherRtpSendInfo sendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key); | 370 | OtherRtpSendInfo sendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(key); |
| 238 | if (sendInfo == null){ | 371 | if (sendInfo == null){ |
| 239 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "未开启发流"); | 372 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "未开启发流"); |
| @@ -251,6 +384,7 @@ public class RtpController { | @@ -251,6 +384,7 @@ public class RtpController { | ||
| 251 | }else { | 384 | }else { |
| 252 | logger.info("[第三方服务对接->关闭发送流] 成功 callId->{}", callId); | 385 | logger.info("[第三方服务对接->关闭发送流] 成功 callId->{}", callId); |
| 253 | } | 386 | } |
| 387 | + redisTemplate.delete(key); | ||
| 254 | } | 388 | } |
| 255 | 389 | ||
| 256 | } | 390 | } |