Commit bfae9780f75db7495f53511f3116bb6c0470a0b0
1 parent
def56793
增加流关闭时的处理
Showing
6 changed files
with
158 additions
and
118 deletions
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisMsgListenConfig.java
| @@ -43,6 +43,9 @@ public class RedisMsgListenConfig { | @@ -43,6 +43,9 @@ public class RedisMsgListenConfig { | ||
| 43 | @Autowired | 43 | @Autowired |
| 44 | private RedisPushStreamResponseListener redisPushStreamResponseListener; | 44 | private RedisPushStreamResponseListener redisPushStreamResponseListener; |
| 45 | 45 | ||
| 46 | + @Autowired | ||
| 47 | + private RedisPushStreamCloseResponseListener redisPushStreamCloseResponseListener; | ||
| 48 | + | ||
| 46 | 49 | ||
| 47 | /** | 50 | /** |
| 48 | * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器 | 51 | * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器 |
| @@ -63,7 +66,7 @@ public class RedisMsgListenConfig { | @@ -63,7 +66,7 @@ public class RedisMsgListenConfig { | ||
| 63 | container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE)); | 66 | container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE)); |
| 64 | container.addMessageListener(redisPushStreamListMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_LIST_CHANGE)); | 67 | container.addMessageListener(redisPushStreamListMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_LIST_CHANGE)); |
| 65 | container.addMessageListener(redisPushStreamResponseListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_RESPONSE)); | 68 | container.addMessageListener(redisPushStreamResponseListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_RESPONSE)); |
| 66 | -// container.addMessageListener(, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_CLOSE_REQUESTED)); | 69 | + container.addMessageListener(redisPushStreamCloseResponseListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_CLOSE_REQUESTED)); |
| 67 | return container; | 70 | return container; |
| 68 | } | 71 | } |
| 69 | } | 72 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
| @@ -283,7 +283,7 @@ public class SIPRequestHeaderPlarformProvider { | @@ -283,7 +283,7 @@ public class SIPRequestHeaderPlarformProvider { | ||
| 283 | viaHeader.setRPort(); | 283 | viaHeader.setRPort(); |
| 284 | viaHeaders.add(viaHeader); | 284 | viaHeaders.add(viaHeader); |
| 285 | // from | 285 | // from |
| 286 | - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(platform.getDeviceGBId(), | 286 | + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sendRtpItem.getChannelId(), |
| 287 | platform.getDeviceIp() + ":" + platform.getDevicePort()); | 287 | platform.getDeviceIp() + ":" + platform.getDevicePort()); |
| 288 | Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); | 288 | Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); |
| 289 | FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, sendRtpItem.getToTag()); | 289 | FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, sendRtpItem.getToTag()); |
| @@ -296,13 +296,10 @@ public class SIPRequestHeaderPlarformProvider { | @@ -296,13 +296,10 @@ public class SIPRequestHeaderPlarformProvider { | ||
| 296 | MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); | 296 | MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); |
| 297 | // ceq | 297 | // ceq |
| 298 | CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE); | 298 | CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE); |
| 299 | - MessageFactoryImpl messageFactory = (MessageFactoryImpl) SipFactory.getInstance().createMessageFactory(); | ||
| 300 | - // 设置编码, 防止中文乱码 | ||
| 301 | - messageFactory.setDefaultContentEncodingCharset("gb2312"); | ||
| 302 | 299 | ||
| 303 | CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(sendRtpItem.getCallId()); | 300 | CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(sendRtpItem.getCallId()); |
| 304 | 301 | ||
| 305 | - request = (SIPRequest) messageFactory.createRequest(requestURI, Request.BYE, callIdHeader, cSeqHeader, fromHeader, | 302 | + request = (SIPRequest) SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.BYE, callIdHeader, cSeqHeader, fromHeader, |
| 306 | toHeader, viaHeaders, maxForwards); | 303 | toHeader, viaHeaders, maxForwards); |
| 307 | 304 | ||
| 308 | request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); | 305 | request.addHeader(SipUtils.createUserAgentHeader(gitUtil)); |
| @@ -310,6 +307,7 @@ public class SIPRequestHeaderPlarformProvider { | @@ -310,6 +307,7 @@ public class SIPRequestHeaderPlarformProvider { | ||
| 310 | String sipAddress = platform.getDeviceIp() + ":" + platform.getDevicePort(); | 307 | String sipAddress = platform.getDeviceIp() + ":" + platform.getDevicePort(); |
| 311 | Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory() | 308 | Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory() |
| 312 | .createSipURI(platform.getDeviceGBId(), sipAddress)); | 309 | .createSipURI(platform.getDeviceGBId(), sipAddress)); |
| 310 | + | ||
| 313 | request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); | 311 | request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); |
| 314 | 312 | ||
| 315 | return request; | 313 | return request; |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| @@ -347,10 +347,9 @@ public class SIPCommander implements ISIPCommander { | @@ -347,10 +347,9 @@ public class SIPCommander implements ISIPCommander { | ||
| 347 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | 347 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| 348 | errorEvent.response(e); | 348 | errorEvent.response(e); |
| 349 | }), e -> { | 349 | }), e -> { |
| 350 | - // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 | ||
| 351 | ResponseEvent responseEvent = (ResponseEvent) e.event; | 350 | ResponseEvent responseEvent = (ResponseEvent) e.event; |
| 352 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); | 351 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); |
| 353 | - streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play); | 352 | + streamSession.put(device.getDeviceId(), channelId, e.callId, stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play); |
| 354 | okEvent.response(e); | 353 | okEvent.response(e); |
| 355 | }); | 354 | }); |
| 356 | } | 355 | } |
| @@ -452,7 +451,7 @@ public class SIPCommander implements ISIPCommander { | @@ -452,7 +451,7 @@ public class SIPCommander implements ISIPCommander { | ||
| 452 | sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { | 451 | sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { |
| 453 | ResponseEvent responseEvent = (ResponseEvent) event.event; | 452 | ResponseEvent responseEvent = (ResponseEvent) event.event; |
| 454 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); | 453 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); |
| 455 | - streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.playback); | 454 | + streamSession.put(device.getDeviceId(), channelId, event.callId, ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.playback); |
| 456 | okEvent.response(event); | 455 | okEvent.response(event); |
| 457 | }); | 456 | }); |
| 458 | if (inviteStreamCallback != null) { | 457 | if (inviteStreamCallback != null) { |
| @@ -580,7 +579,7 @@ public class SIPCommander implements ISIPCommander { | @@ -580,7 +579,7 @@ public class SIPCommander implements ISIPCommander { | ||
| 580 | if (ssrcIndex >= 0) { | 579 | if (ssrcIndex >= 0) { |
| 581 | ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); | 580 | ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); |
| 582 | } | 581 | } |
| 583 | - streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download); | 582 | + streamSession.put(device.getDeviceId(), channelId, newCallIdHeader.getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download); |
| 584 | okEvent.response(event); | 583 | okEvent.response(event); |
| 585 | }); | 584 | }); |
| 586 | } | 585 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
| @@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor | @@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor | ||
| 11 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; | 11 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| 12 | import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; | 12 | import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
| 13 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 13 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 14 | +import com.genersoft.iot.vmp.service.IDeviceChannelService; | ||
| 14 | import com.genersoft.iot.vmp.service.IDeviceService; | 15 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 15 | import com.genersoft.iot.vmp.service.IMediaServerService; | 16 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 16 | import com.genersoft.iot.vmp.service.IPlatformService; | 17 | import com.genersoft.iot.vmp.service.IPlatformService; |
| @@ -27,11 +28,7 @@ import org.springframework.stereotype.Component; | @@ -27,11 +28,7 @@ import org.springframework.stereotype.Component; | ||
| 27 | import javax.sip.InvalidArgumentException; | 28 | import javax.sip.InvalidArgumentException; |
| 28 | import javax.sip.RequestEvent; | 29 | import javax.sip.RequestEvent; |
| 29 | import javax.sip.SipException; | 30 | import javax.sip.SipException; |
| 30 | -import javax.sip.address.SipURI; | ||
| 31 | import javax.sip.header.CallIdHeader; | 31 | import javax.sip.header.CallIdHeader; |
| 32 | -import javax.sip.header.FromHeader; | ||
| 33 | -import javax.sip.header.HeaderAddress; | ||
| 34 | -import javax.sip.header.ToHeader; | ||
| 35 | import javax.sip.message.Response; | 32 | import javax.sip.message.Response; |
| 36 | import java.text.ParseException; | 33 | import java.text.ParseException; |
| 37 | import java.util.HashMap; | 34 | import java.util.HashMap; |
| @@ -59,6 +56,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | @@ -59,6 +56,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | ||
| 59 | private IDeviceService deviceService; | 56 | private IDeviceService deviceService; |
| 60 | 57 | ||
| 61 | @Autowired | 58 | @Autowired |
| 59 | + private IDeviceChannelService channelService; | ||
| 60 | + | ||
| 61 | + @Autowired | ||
| 62 | private IVideoManagerStorage storager; | 62 | private IVideoManagerStorage storager; |
| 63 | 63 | ||
| 64 | @Autowired | 64 | @Autowired |
| @@ -88,95 +88,91 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | @@ -88,95 +88,91 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In | ||
| 88 | */ | 88 | */ |
| 89 | @Override | 89 | @Override |
| 90 | public void process(RequestEvent evt) { | 90 | public void process(RequestEvent evt) { |
| 91 | - | 91 | + SIPRequest request = (SIPRequest) evt.getRequest(); |
| 92 | try { | 92 | try { |
| 93 | - responseAck((SIPRequest) evt.getRequest(), Response.OK); | 93 | + responseAck(request, Response.OK); |
| 94 | } catch (SipException | InvalidArgumentException | ParseException e) { | 94 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 95 | logger.error("[回复BYE信息失败],{}", e.getMessage()); | 95 | logger.error("[回复BYE信息失败],{}", e.getMessage()); |
| 96 | } | 96 | } |
| 97 | CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); | 97 | CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); |
| 98 | - String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); | ||
| 99 | - String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); | ||
| 100 | - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId, null, callIdHeader.getCallId()); | ||
| 101 | - logger.info("[收到bye] {}/{}", platformGbId, channelId); | ||
| 102 | - if (sendRtpItem != null){ | ||
| 103 | - String streamId = sendRtpItem.getStreamId(); | ||
| 104 | - Map<String, Object> param = new HashMap<>(); | ||
| 105 | - param.put("vhost","__defaultVhost__"); | ||
| 106 | - param.put("app",sendRtpItem.getApp()); | ||
| 107 | - param.put("stream",streamId); | ||
| 108 | - param.put("ssrc",sendRtpItem.getSsrc()); | ||
| 109 | - logger.info("[收到bye] 停止向上级推流:{}", streamId); | ||
| 110 | - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); | ||
| 111 | - redisCatchStorage.deleteSendRTPServer(platformGbId, channelId, callIdHeader.getCallId(), null); | ||
| 112 | - zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); | ||
| 113 | - if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) { | ||
| 114 | - ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); | ||
| 115 | - if (platform != null) { | ||
| 116 | - MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, | ||
| 117 | - sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), | ||
| 118 | - sendRtpItem.getPlatformId(), platform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); | ||
| 119 | - messageForPushChannel.setPlatFormIndex(platform.getId()); | ||
| 120 | - redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); | ||
| 121 | - }else { | ||
| 122 | - logger.info("[上级平台停止观看] 未找到平台{}的信息,发送redis消息失败", sendRtpItem.getPlatformId()); | ||
| 123 | - } | ||
| 124 | - } | ||
| 125 | 98 | ||
| 126 | - int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId); | ||
| 127 | - if (totalReaderCount <= 0) { | ||
| 128 | - logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId); | ||
| 129 | - if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) { | ||
| 130 | - Device device = deviceService.getDevice(sendRtpItem.getDeviceId()); | ||
| 131 | - if (device == null) { | ||
| 132 | - logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId); | ||
| 133 | - } | ||
| 134 | - try { | ||
| 135 | - logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), channelId); | ||
| 136 | - cmder.streamByeCmd(device, channelId, streamId, null); | ||
| 137 | - } catch (InvalidArgumentException | ParseException | SipException | | ||
| 138 | - SsrcTransactionNotFoundException e) { | ||
| 139 | - logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); | ||
| 140 | - } | ||
| 141 | - } | ||
| 142 | -// if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) { | ||
| 143 | -// MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, | ||
| 144 | -// sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), | ||
| 145 | -// sendRtpItem.getPlatformId(), null, null, sendRtpItem.getMediaServerId()); | ||
| 146 | -// redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel); | ||
| 147 | -// } | 99 | + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); |
| 100 | + | ||
| 101 | + if (sendRtpItem != null){ | ||
| 102 | + logger.info("[收到bye] 来自平台{}, 停止通道:{}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId()); | ||
| 103 | + String streamId = sendRtpItem.getStreamId(); | ||
| 104 | + Map<String, Object> param = new HashMap<>(); | ||
| 105 | + param.put("vhost","__defaultVhost__"); | ||
| 106 | + param.put("app",sendRtpItem.getApp()); | ||
| 107 | + param.put("stream",streamId); | ||
| 108 | + param.put("ssrc",sendRtpItem.getSsrc()); | ||
| 109 | + logger.info("[收到bye] 停止向上级推流:{}", streamId); | ||
| 110 | + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); | ||
| 111 | + redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), | ||
| 112 | + callIdHeader.getCallId(), null); | ||
| 113 | + zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); | ||
| 114 | + if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) { | ||
| 115 | + ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); | ||
| 116 | + if (platform != null) { | ||
| 117 | + MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, | ||
| 118 | + sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), | ||
| 119 | + sendRtpItem.getPlatformId(), platform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); | ||
| 120 | + messageForPushChannel.setPlatFormIndex(platform.getId()); | ||
| 121 | + redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); | ||
| 122 | + }else { | ||
| 123 | + logger.info("[上级平台停止观看] 未找到平台{}的信息,发送redis消息失败", sendRtpItem.getPlatformId()); | ||
| 148 | } | 124 | } |
| 149 | } | 125 | } |
| 150 | - // 可能是设备主动停止 | ||
| 151 | - Device device = storager.queryVideoDeviceByChannelId(platformGbId); | ||
| 152 | - if (device != null) { | ||
| 153 | - storager.stopPlay(device.getDeviceId(), channelId); | ||
| 154 | - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId); | ||
| 155 | - if (streamInfo != null) { | ||
| 156 | - redisCatchStorage.stopPlay(streamInfo); | ||
| 157 | - mediaServerService.closeRTPServer(streamInfo.getMediaServerId(), streamInfo.getStream()); | ||
| 158 | - } | ||
| 159 | - SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null); | ||
| 160 | - if (ssrcTransactionForPlay != null){ | ||
| 161 | - if (ssrcTransactionForPlay.getCallId().equals(callIdHeader.getCallId())){ | ||
| 162 | - // 释放ssrc | ||
| 163 | - MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlay.getMediaServerId()); | ||
| 164 | - if (mediaServerItem != null) { | ||
| 165 | - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlay.getSsrc()); | ||
| 166 | - } | ||
| 167 | - streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream()); | 126 | + |
| 127 | + int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId); | ||
| 128 | + if (totalReaderCount <= 0) { | ||
| 129 | + logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId); | ||
| 130 | + if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) { | ||
| 131 | + Device device = deviceService.getDevice(sendRtpItem.getDeviceId()); | ||
| 132 | + if (device == null) { | ||
| 133 | + logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId); | ||
| 168 | } | 134 | } |
| 169 | - } | ||
| 170 | - SsrcTransaction ssrcTransactionForPlayBack = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callIdHeader.getCallId(), null); | ||
| 171 | - if (ssrcTransactionForPlayBack != null) { | ||
| 172 | - // 释放ssrc | ||
| 173 | - MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlayBack.getMediaServerId()); | ||
| 174 | - if (mediaServerItem != null) { | ||
| 175 | - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlayBack.getSsrc()); | 135 | + try { |
| 136 | + logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); | ||
| 137 | + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null); | ||
| 138 | + } catch (InvalidArgumentException | ParseException | SipException | | ||
| 139 | + SsrcTransactionNotFoundException e) { | ||
| 140 | + logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); | ||
| 176 | } | 141 | } |
| 177 | - streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlayBack.getStream()); | ||
| 178 | } | 142 | } |
| 179 | } | 143 | } |
| 144 | + }else { | ||
| 145 | + // 可能是设备发送的停止 | ||
| 146 | + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); | ||
| 147 | + if (ssrcTransaction == null) { | ||
| 148 | + logger.info("[收到bye] 但是无法获取推流信息和发流信息,忽略此请求"); | ||
| 149 | + logger.info(request.toString()); | ||
| 150 | + return; | ||
| 151 | + } | ||
| 152 | + logger.info("[收到bye] 来自设备:{}, 通道已停止推流: {}", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); | ||
| 180 | 153 | ||
| 154 | + Device device = deviceService.getDevice(ssrcTransaction.getDeviceId()); | ||
| 155 | + if (device == null) { | ||
| 156 | + logger.info("[收到bye] 未找到设备:{} ", ssrcTransaction.getDeviceId()); | ||
| 157 | + return; | ||
| 158 | + } | ||
| 159 | + DeviceChannel channel = channelService.getOne(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); | ||
| 160 | + if (channel == null) { | ||
| 161 | + logger.info("[收到bye] 未找到通道,设备:{}, 通道:{}", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); | ||
| 162 | + return; | ||
| 163 | + } | ||
| 164 | + storager.stopPlay(device.getDeviceId(), channel.getChannelId()); | ||
| 165 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channel.getChannelId()); | ||
| 166 | + if (streamInfo != null) { | ||
| 167 | + redisCatchStorage.stopPlay(streamInfo); | ||
| 168 | + mediaServerService.closeRTPServer(streamInfo.getMediaServerId(), streamInfo.getStream()); | ||
| 169 | + } | ||
| 170 | + // 释放ssrc | ||
| 171 | + MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId()); | ||
| 172 | + if (mediaServerItem != null) { | ||
| 173 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc()); | ||
| 174 | + } | ||
| 175 | + streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcTransaction.getStream()); | ||
| 176 | + } | ||
| 181 | } | 177 | } |
| 182 | } | 178 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| @@ -143,7 +143,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -143,7 +143,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 143 | if (rtpInfo.getBoolean("exist")) { | 143 | if (rtpInfo.getBoolean("exist")) { |
| 144 | int localPort = rtpInfo.getInteger("local_port"); | 144 | int localPort = rtpInfo.getInteger("local_port"); |
| 145 | if (localPort == 0) { | 145 | if (localPort == 0) { |
| 146 | - logger.warn("[点播],点播时发现rtpServerC存在,但是尚未开始推流"); | 146 | + logger.warn("[点播],点播时发现rtpServer存在,但是尚未开始推流"); |
| 147 | // 此时说明rtpServer已经创建但是流还没有推上来 | 147 | // 此时说明rtpServer已经创建但是流还没有推上来 |
| 148 | WVPResult wvpResult = new WVPResult(); | 148 | WVPResult wvpResult = new WVPResult(); |
| 149 | wvpResult.setCode(ErrorCode.ERROR100.getCode()); | 149 | wvpResult.setCode(ErrorCode.ERROR100.getCode()); |
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java
| 1 | package com.genersoft.iot.vmp.service.redisMsg; | 1 | package com.genersoft.iot.vmp.service.redisMsg; |
| 2 | 2 | ||
| 3 | import com.alibaba.fastjson2.JSON; | 3 | import com.alibaba.fastjson2.JSON; |
| 4 | +import com.genersoft.iot.vmp.conf.UserSetting; | ||
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType; | ||
| 6 | +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | ||
| 7 | +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; | ||
| 8 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; | ||
| 9 | +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; | ||
| 10 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | ||
| 11 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; | ||
| 12 | +import com.genersoft.iot.vmp.service.IMediaServerService; | ||
| 13 | +import com.genersoft.iot.vmp.service.IStreamPushService; | ||
| 14 | +import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; | ||
| 4 | import com.genersoft.iot.vmp.service.bean.MessageForPushChannelResponse; | 15 | import com.genersoft.iot.vmp.service.bean.MessageForPushChannelResponse; |
| 16 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 17 | +import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | ||
| 5 | import org.slf4j.Logger; | 18 | import org.slf4j.Logger; |
| 6 | import org.slf4j.LoggerFactory; | 19 | import org.slf4j.LoggerFactory; |
| 7 | import org.springframework.beans.factory.annotation.Autowired; | 20 | import org.springframework.beans.factory.annotation.Autowired; |
| 8 | -import org.springframework.beans.factory.annotation.Qualifier; | ||
| 9 | import org.springframework.data.redis.connection.Message; | 21 | import org.springframework.data.redis.connection.Message; |
| 10 | import org.springframework.data.redis.connection.MessageListener; | 22 | import org.springframework.data.redis.connection.MessageListener; |
| 11 | -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||
| 12 | import org.springframework.stereotype.Component; | 23 | import org.springframework.stereotype.Component; |
| 13 | -import org.springframework.util.ObjectUtils; | ||
| 14 | 24 | ||
| 25 | +import javax.sip.InvalidArgumentException; | ||
| 26 | +import javax.sip.SipException; | ||
| 27 | +import java.text.ParseException; | ||
| 28 | +import java.util.HashMap; | ||
| 29 | +import java.util.List; | ||
| 15 | import java.util.Map; | 30 | import java.util.Map; |
| 16 | import java.util.concurrent.ConcurrentHashMap; | 31 | import java.util.concurrent.ConcurrentHashMap; |
| 17 | -import java.util.concurrent.ConcurrentLinkedQueue; | ||
| 18 | 32 | ||
| 19 | /** | 33 | /** |
| 20 | * 接收redis发送的结束推流请求 | 34 | * 接收redis发送的结束推流请求 |
| @@ -25,11 +39,26 @@ public class RedisPushStreamCloseResponseListener implements MessageListener { | @@ -25,11 +39,26 @@ public class RedisPushStreamCloseResponseListener implements MessageListener { | ||
| 25 | 39 | ||
| 26 | private final static Logger logger = LoggerFactory.getLogger(RedisPushStreamCloseResponseListener.class); | 40 | private final static Logger logger = LoggerFactory.getLogger(RedisPushStreamCloseResponseListener.class); |
| 27 | 41 | ||
| 28 | - private ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>(); | 42 | + @Autowired |
| 43 | + private IStreamPushService streamPushService; | ||
| 44 | + | ||
| 45 | + @Autowired | ||
| 46 | + private IRedisCatchStorage redisCatchStorage; | ||
| 29 | 47 | ||
| 30 | - @Qualifier("taskExecutor") | ||
| 31 | @Autowired | 48 | @Autowired |
| 32 | - private ThreadPoolTaskExecutor taskExecutor; | 49 | + private IVideoManagerStorage storager; |
| 50 | + | ||
| 51 | + @Autowired | ||
| 52 | + private ISIPCommanderForPlatform commanderFroPlatform; | ||
| 53 | + | ||
| 54 | + @Autowired | ||
| 55 | + private UserSetting userSetting; | ||
| 56 | + | ||
| 57 | + @Autowired | ||
| 58 | + private IMediaServerService mediaServerService; | ||
| 59 | + | ||
| 60 | + @Autowired | ||
| 61 | + private ZLMRTPServerFactory zlmrtpServerFactory; | ||
| 33 | 62 | ||
| 34 | 63 | ||
| 35 | private Map<String, PushStreamResponseEvent> responseEvents = new ConcurrentHashMap<>(); | 64 | private Map<String, PushStreamResponseEvent> responseEvents = new ConcurrentHashMap<>(); |
| @@ -40,30 +69,45 @@ public class RedisPushStreamCloseResponseListener implements MessageListener { | @@ -40,30 +69,45 @@ public class RedisPushStreamCloseResponseListener implements MessageListener { | ||
| 40 | 69 | ||
| 41 | @Override | 70 | @Override |
| 42 | public void onMessage(Message message, byte[] bytes) { | 71 | public void onMessage(Message message, byte[] bytes) { |
| 43 | - logger.info("[REDIS消息-请求推流结果]: {}", new String(message.getBody())); | ||
| 44 | - boolean isEmpty = taskQueue.isEmpty(); | ||
| 45 | - taskQueue.offer(message); | ||
| 46 | - if (isEmpty) { | ||
| 47 | - taskExecutor.execute(() -> { | ||
| 48 | - while (!taskQueue.isEmpty()) { | ||
| 49 | - Message msg = taskQueue.poll(); | ||
| 50 | - try { | ||
| 51 | - MessageForPushChannelResponse response = JSON.parseObject(new String(msg.getBody()), MessageForPushChannelResponse.class); | ||
| 52 | - if (response == null || ObjectUtils.isEmpty(response.getApp()) || ObjectUtils.isEmpty(response.getStream())){ | ||
| 53 | - logger.info("[REDIS消息-请求推流结果]:参数不全"); | ||
| 54 | - continue; | 72 | + logger.info("[REDIS消息-推流结束]: {}", new String(message.getBody())); |
| 73 | + MessageForPushChannel pushChannel = JSON.parseObject(message.getBody(), MessageForPushChannel.class); | ||
| 74 | + StreamPushItem push = streamPushService.getPush(pushChannel.getApp(), pushChannel.getStream()); | ||
| 75 | + if (push != null) { | ||
| 76 | + if (redisCatchStorage.isChannelSendingRTP(push.getGbId())) { | ||
| 77 | + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId( | ||
| 78 | + push.getGbId()); | ||
| 79 | + if (sendRtpItems.size() > 0) { | ||
| 80 | + for (SendRtpItem sendRtpItem : sendRtpItems) { | ||
| 81 | + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); | ||
| 82 | + // 停止向上级推流 | ||
| 83 | + String streamId = sendRtpItem.getStreamId(); | ||
| 84 | + Map<String, Object> param = new HashMap<>(); | ||
| 85 | + param.put("vhost","__defaultVhost__"); | ||
| 86 | + param.put("app",sendRtpItem.getApp()); | ||
| 87 | + param.put("stream",streamId); | ||
| 88 | + param.put("ssrc",sendRtpItem.getSsrc()); | ||
| 89 | + logger.info("[REDIS消息-推流结束] 停止向上级推流:{}", streamId); | ||
| 90 | + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); | ||
| 91 | + redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | ||
| 92 | + zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); | ||
| 93 | + | ||
| 94 | + try { | ||
| 95 | + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem); | ||
| 96 | + } catch (SipException | InvalidArgumentException | ParseException e) { | ||
| 97 | + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); | ||
| 55 | } | 98 | } |
| 56 | - // 查看正在等待的invite消息 | ||
| 57 | - if (responseEvents.get(response.getApp() + response.getStream()) != null) { | ||
| 58 | - responseEvents.get(response.getApp() + response.getStream()).run(response); | 99 | + if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) { |
| 100 | + MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, | ||
| 101 | + sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), | ||
| 102 | + sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); | ||
| 103 | + messageForPushChannel.setPlatFormIndex(parentPlatform.getId()); | ||
| 104 | + redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); | ||
| 59 | } | 105 | } |
| 60 | - }catch (Exception e) { | ||
| 61 | - logger.warn("[REDIS消息-请求推流结果] 发现未处理的异常, \r\n{}", JSON.toJSONString(message)); | ||
| 62 | - logger.error("[REDIS消息-请求推流结果] 异常内容: ", e); | ||
| 63 | } | 106 | } |
| 64 | } | 107 | } |
| 65 | - }); | 108 | + } |
| 66 | } | 109 | } |
| 110 | + | ||
| 67 | } | 111 | } |
| 68 | 112 | ||
| 69 | public void addEvent(String app, String stream, PushStreamResponseEvent callback) { | 113 | public void addEvent(String app, String stream, PushStreamResponseEvent callback) { |