Commit d46fc9de827fe85a48f447cf1550444573a6f1a5
1 parent
1f02cb91
优化下级平台自定义ssrc的情况,优化国标录像下载流程
Showing
9 changed files
with
141 additions
and
20 deletions
src/main/java/com/genersoft/iot/vmp/common/CommonCallback.java
0 → 100644
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| @@ -546,7 +546,7 @@ public class SIPCommander implements ISIPCommander { | @@ -546,7 +546,7 @@ public class SIPCommander implements ISIPCommander { | ||
| 546 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); | 546 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); |
| 547 | // 添加订阅 | 547 | // 添加订阅 |
| 548 | CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); | 548 | CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); |
| 549 | - String callId=newCallIdHeader.getCallId(); | 549 | + String callId= newCallIdHeader.getCallId(); |
| 550 | subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { | 550 | subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { |
| 551 | logger.debug("sipc 添加订阅===callId {}",callId); | 551 | logger.debug("sipc 添加订阅===callId {}",callId); |
| 552 | hookEvent.call(new InviteStreamInfo(mediaServerItem, json,callId, "rtp", ssrcInfo.getStream())); | 552 | hookEvent.call(new InviteStreamInfo(mediaServerItem, json,callId, "rtp", ssrcInfo.getStream())); |
| @@ -558,7 +558,7 @@ public class SIPCommander implements ISIPCommander { | @@ -558,7 +558,7 @@ public class SIPCommander implements ISIPCommander { | ||
| 558 | (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> { | 558 | (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> { |
| 559 | logger.info("[录像]下载结束, 发送BYE"); | 559 | logger.info("[录像]下载结束, 发送BYE"); |
| 560 | try { | 560 | try { |
| 561 | - streamByeCmd(device, channelId, ssrcInfo.getStream(),callId); | 561 | + streamByeCmd(device, channelId, ssrcInfo.getStream(), callId); |
| 562 | } catch (InvalidArgumentException | ParseException | SipException | | 562 | } catch (InvalidArgumentException | ParseException | SipException | |
| 563 | SsrcTransactionNotFoundException e) { | 563 | SsrcTransactionNotFoundException e) { |
| 564 | logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); | 564 | logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); |
| @@ -580,8 +580,6 @@ public class SIPCommander implements ISIPCommander { | @@ -580,8 +580,6 @@ public class SIPCommander implements ISIPCommander { | ||
| 580 | if (ssrcIndex >= 0) { | 580 | if (ssrcIndex >= 0) { |
| 581 | ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); | 581 | ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); |
| 582 | } | 582 | } |
| 583 | - logger.debug("接收到的下载响应ssrc====>{}",ssrcInfo.getSsrc()); | ||
| 584 | - logger.debug("接收到的下载响应ssrc====>{}",ssrc); | ||
| 585 | streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download); | 583 | streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download); |
| 586 | okEvent.response(event); | 584 | okEvent.response(event); |
| 587 | }); | 585 | }); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
| @@ -12,6 +12,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; | @@ -12,6 +12,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; | ||
| 12 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; | 12 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| 13 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; | 13 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| 14 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; | 14 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; |
| 15 | +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | ||
| 16 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | ||
| 17 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | ||
| 15 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | 18 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 16 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | 19 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 17 | import gov.nist.javax.sip.message.SIPRequest; | 20 | import gov.nist.javax.sip.message.SIPRequest; |
| @@ -58,6 +61,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i | @@ -58,6 +61,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i | ||
| 58 | @Autowired | 61 | @Autowired |
| 59 | private VideoStreamSessionManager sessionManager; | 62 | private VideoStreamSessionManager sessionManager; |
| 60 | 63 | ||
| 64 | + @Autowired | ||
| 65 | + private ZlmHttpHookSubscribe subscribe; | ||
| 66 | + | ||
| 61 | @Override | 67 | @Override |
| 62 | public void afterPropertiesSet() throws Exception { | 68 | public void afterPropertiesSet() throws Exception { |
| 63 | notifyMessageHandler.addHandler(cmdType, this); | 69 | notifyMessageHandler.addHandler(cmdType, this); |
| @@ -93,6 +99,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i | @@ -93,6 +99,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i | ||
| 93 | } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) { | 99 | } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) { |
| 94 | logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage()); | 100 | logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage()); |
| 95 | } | 101 | } |
| 102 | + // 去除监听流注销自动停止下载的监听 | ||
| 103 | + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcTransaction.getStream(), false, "rtsp", ssrcTransaction.getMediaServerId()); | ||
| 104 | + subscribe.removeSubscribe(hookSubscribe); | ||
| 96 | 105 | ||
| 97 | // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定 | 106 | // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定 |
| 98 | SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null); | 107 | SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null); |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
| @@ -276,6 +276,10 @@ public class ZLMRESTfulUtils { | @@ -276,6 +276,10 @@ public class ZLMRESTfulUtils { | ||
| 276 | return sendPost(mediaServerItem, "closeRtpServer",param, null); | 276 | return sendPost(mediaServerItem, "closeRtpServer",param, null); |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | + public void closeRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param, RequestCallback callback) { | ||
| 280 | + sendPost(mediaServerItem, "closeRtpServer",param, callback); | ||
| 281 | + } | ||
| 282 | + | ||
| 279 | public JSONObject listRtpServer(MediaServerItem mediaServerItem) { | 283 | public JSONObject listRtpServer(MediaServerItem mediaServerItem) { |
| 280 | return sendPost(mediaServerItem, "listRtpServer",null, null); | 284 | return sendPost(mediaServerItem, "listRtpServer",null, null); |
| 281 | } | 285 | } |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.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.JSONArray; | 4 | import com.alibaba.fastjson2.JSONArray; |
| 5 | import com.alibaba.fastjson2.JSONObject; | 5 | import com.alibaba.fastjson2.JSONObject; |
| 6 | +import com.genersoft.iot.vmp.common.CommonCallback; | ||
| 6 | import com.genersoft.iot.vmp.conf.UserSetting; | 7 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 7 | import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; | 8 | import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; |
| 8 | import com.genersoft.iot.vmp.media.zlm.dto.*; | 9 | import com.genersoft.iot.vmp.media.zlm.dto.*; |
| @@ -164,6 +165,31 @@ public class ZLMRTPServerFactory { | @@ -164,6 +165,31 @@ public class ZLMRTPServerFactory { | ||
| 164 | return result; | 165 | return result; |
| 165 | } | 166 | } |
| 166 | 167 | ||
| 168 | + public void closeRtpServer(MediaServerItem serverItem, String streamId, CommonCallback<Boolean> callback) { | ||
| 169 | + if (serverItem == null) { | ||
| 170 | + callback.run(false); | ||
| 171 | + return; | ||
| 172 | + } | ||
| 173 | + Map<String, Object> param = new HashMap<>(); | ||
| 174 | + param.put("stream_id", streamId); | ||
| 175 | + zlmresTfulUtils.closeRtpServer(serverItem, param, jsonObject -> { | ||
| 176 | + if (jsonObject != null ) { | ||
| 177 | + if (jsonObject.getInteger("code") == 0) { | ||
| 178 | + callback.run(jsonObject.getInteger("hit") == 1); | ||
| 179 | + return; | ||
| 180 | + }else { | ||
| 181 | + logger.error("关闭RTP Server 失败: " + jsonObject.getString("msg")); | ||
| 182 | + } | ||
| 183 | + }else { | ||
| 184 | + // 检查ZLM状态 | ||
| 185 | + logger.error("关闭RTP Server 失败: 请检查ZLM服务"); | ||
| 186 | + } | ||
| 187 | + callback.run(false); | ||
| 188 | + }); | ||
| 189 | + | ||
| 190 | + | ||
| 191 | + } | ||
| 192 | + | ||
| 167 | 193 | ||
| 168 | /** | 194 | /** |
| 169 | * 创建一个国标推流 | 195 | * 创建一个国标推流 |
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
| 1 | package com.genersoft.iot.vmp.service; | 1 | package com.genersoft.iot.vmp.service; |
| 2 | 2 | ||
| 3 | +import com.genersoft.iot.vmp.common.CommonCallback; | ||
| 3 | import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; | 4 | import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; |
| 4 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 5 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 5 | import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData; | 6 | import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData; |
| @@ -51,6 +52,8 @@ public interface IMediaServerService { | @@ -51,6 +52,8 @@ public interface IMediaServerService { | ||
| 51 | 52 | ||
| 52 | void closeRTPServer(MediaServerItem mediaServerItem, String streamId); | 53 | void closeRTPServer(MediaServerItem mediaServerItem, String streamId); |
| 53 | 54 | ||
| 55 | + void closeRTPServer(MediaServerItem mediaServerItem, String streamId, CommonCallback<Boolean> callback); | ||
| 56 | + | ||
| 54 | void closeRTPServer(String mediaServerId, String streamId); | 57 | void closeRTPServer(String mediaServerId, String streamId); |
| 55 | 58 | ||
| 56 | void clearRTPServer(MediaServerItem mediaServerItem); | 59 | void clearRTPServer(MediaServerItem mediaServerItem); |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.service.impl; | @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.service.impl; | ||
| 3 | import com.alibaba.fastjson2.JSON; | 3 | import com.alibaba.fastjson2.JSON; |
| 4 | import com.alibaba.fastjson2.JSONArray; | 4 | import com.alibaba.fastjson2.JSONArray; |
| 5 | import com.alibaba.fastjson2.JSONObject; | 5 | import com.alibaba.fastjson2.JSONObject; |
| 6 | +import com.genersoft.iot.vmp.common.CommonCallback; | ||
| 6 | import com.genersoft.iot.vmp.common.VideoManagerConstants; | 7 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 7 | import com.genersoft.iot.vmp.conf.DynamicTask; | 8 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 8 | import com.genersoft.iot.vmp.conf.SipConfig; | 9 | import com.genersoft.iot.vmp.conf.SipConfig; |
| @@ -173,6 +174,15 @@ public class MediaServerServiceImpl implements IMediaServerService { | @@ -173,6 +174,15 @@ public class MediaServerServiceImpl implements IMediaServerService { | ||
| 173 | } | 174 | } |
| 174 | 175 | ||
| 175 | @Override | 176 | @Override |
| 177 | + public void closeRTPServer(MediaServerItem mediaServerItem, String streamId, CommonCallback<Boolean> callback) { | ||
| 178 | + if (mediaServerItem == null) { | ||
| 179 | + callback.run(false); | ||
| 180 | + return; | ||
| 181 | + } | ||
| 182 | + zlmrtpServerFactory.closeRtpServer(mediaServerItem, streamId, callback); | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + @Override | ||
| 176 | public void closeRTPServer(String mediaServerId, String streamId) { | 186 | public void closeRTPServer(String mediaServerId, String streamId) { |
| 177 | MediaServerItem mediaServerItem = this.getOne(mediaServerId); | 187 | MediaServerItem mediaServerItem = this.getOne(mediaServerId); |
| 178 | closeRTPServer(mediaServerItem, streamId); | 188 | closeRTPServer(mediaServerItem, streamId); |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| @@ -328,9 +328,30 @@ public class PlayServiceImpl implements IPlayService { | @@ -328,9 +328,30 @@ public class PlayServiceImpl implements IPlayService { | ||
| 328 | }); | 328 | }); |
| 329 | } | 329 | } |
| 330 | // 关闭rtp server | 330 | // 关闭rtp server |
| 331 | - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); | ||
| 332 | - // 重新开启ssrc server | ||
| 333 | - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort()); | 331 | + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{ |
| 332 | + if (result) { | ||
| 333 | + // 重新开启ssrc server | ||
| 334 | + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort()); | ||
| 335 | + }else { | ||
| 336 | + try { | ||
| 337 | + logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId); | ||
| 338 | + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null); | ||
| 339 | + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { | ||
| 340 | + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage()); | ||
| 341 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); | ||
| 342 | + } | ||
| 343 | + | ||
| 344 | + dynamicTask.stop(timeOutTaskKey); | ||
| 345 | + // 释放ssrc | ||
| 346 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | ||
| 347 | + | ||
| 348 | + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | ||
| 349 | + event.msg = "下级自定义了ssrc,重新设置收流信息失败"; | ||
| 350 | + event.statusCode = 500; | ||
| 351 | + errorEvent.response(event); | ||
| 352 | + } | ||
| 353 | + }); | ||
| 354 | + | ||
| 334 | 355 | ||
| 335 | } | 356 | } |
| 336 | } | 357 | } |
| @@ -472,7 +493,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -472,7 +493,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 472 | if (device == null) { | 493 | if (device == null) { |
| 473 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在"); | 494 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在"); |
| 474 | } | 495 | } |
| 475 | - | 496 | + logger.info("[回放消息] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); |
| 476 | PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>(); | 497 | PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>(); |
| 477 | String playBackTimeOutTaskKey = UUID.randomUUID().toString(); | 498 | String playBackTimeOutTaskKey = UUID.randomUUID().toString(); |
| 478 | dynamicTask.startDelay(playBackTimeOutTaskKey, () -> { | 499 | dynamicTask.startDelay(playBackTimeOutTaskKey, () -> { |
| @@ -546,6 +567,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -546,6 +567,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 546 | if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) { | 567 | if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) { |
| 547 | // ssrc 不可用 | 568 | // ssrc 不可用 |
| 548 | // 释放ssrc | 569 | // 释放ssrc |
| 570 | + dynamicTask.stop(playBackTimeOutTaskKey); | ||
| 549 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | 571 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| 550 | streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | 572 | streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| 551 | eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用"; | 573 | eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用"; |
| @@ -568,10 +590,31 @@ public class PlayServiceImpl implements IPlayService { | @@ -568,10 +590,31 @@ public class PlayServiceImpl implements IPlayService { | ||
| 568 | hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream())); | 590 | hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream())); |
| 569 | }); | 591 | }); |
| 570 | } | 592 | } |
| 593 | + | ||
| 571 | // 关闭rtp server | 594 | // 关闭rtp server |
| 572 | - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); | ||
| 573 | - // 重新开启ssrc server | ||
| 574 | - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); | 595 | + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{ |
| 596 | + if (result) { | ||
| 597 | + // 重新开启ssrc server | ||
| 598 | + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); | ||
| 599 | + }else { | ||
| 600 | + try { | ||
| 601 | + logger.warn("[回放消息]停止 {}/{}", device.getDeviceId(), channelId); | ||
| 602 | + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null); | ||
| 603 | + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { | ||
| 604 | + logger.error("[命令发送失败] 停止点播 停止, 发送BYE: {}", e.getMessage()); | ||
| 605 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); | ||
| 606 | + } | ||
| 607 | + | ||
| 608 | + dynamicTask.stop(playBackTimeOutTaskKey); | ||
| 609 | + // 释放ssrc | ||
| 610 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | ||
| 611 | + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | ||
| 612 | + errorEvent.response(eventResult); | ||
| 613 | + eventResult.msg = "下级自定义了ssrc,重新设置收流信息失败"; | ||
| 614 | + eventResult.statusCode = 500; | ||
| 615 | + errorEvent.response(eventResult); | ||
| 616 | + } | ||
| 617 | + }); | ||
| 575 | } | 618 | } |
| 576 | } | 619 | } |
| 577 | } | 620 | } |
| @@ -619,7 +662,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -619,7 +662,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 619 | throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "不存在"); | 662 | throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "不存在"); |
| 620 | } | 663 | } |
| 621 | PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>(); | 664 | PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>(); |
| 622 | - | 665 | + logger.info("[录像下载] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); |
| 623 | String downLoadTimeOutTaskKey = UUID.randomUUID().toString(); | 666 | String downLoadTimeOutTaskKey = UUID.randomUUID().toString(); |
| 624 | dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> { | 667 | dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> { |
| 625 | logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId)); | 668 | logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| @@ -648,7 +691,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -648,7 +691,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 648 | streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | 691 | streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| 649 | }; | 692 | }; |
| 650 | InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> { | 693 | InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> { |
| 651 | - logger.info("收到订阅消息: " + inviteStreamInfo.getCallId()); | 694 | + logger.info("[录像下载]收到订阅消息: " + inviteStreamInfo.getCallId()); |
| 652 | dynamicTask.stop(downLoadTimeOutTaskKey); | 695 | dynamicTask.stop(downLoadTimeOutTaskKey); |
| 653 | StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); | 696 | StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); |
| 654 | streamInfo.setStartTime(startTime); | 697 | streamInfo.setStartTime(startTime); |
| @@ -678,9 +721,9 @@ public class PlayServiceImpl implements IPlayService { | @@ -678,9 +721,9 @@ public class PlayServiceImpl implements IPlayService { | ||
| 678 | if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { | 721 | if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { |
| 679 | return; | 722 | return; |
| 680 | } | 723 | } |
| 681 | - logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse); | 724 | + logger.info("[录像下载] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse); |
| 682 | if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { | 725 | if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { |
| 683 | - logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); | 726 | + logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); |
| 684 | 727 | ||
| 685 | if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) { | 728 | if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) { |
| 686 | // ssrc 不可用 | 729 | // ssrc 不可用 |
| @@ -707,14 +750,34 @@ public class PlayServiceImpl implements IPlayService { | @@ -707,14 +750,34 @@ public class PlayServiceImpl implements IPlayService { | ||
| 707 | hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream())); | 750 | hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream())); |
| 708 | }); | 751 | }); |
| 709 | } | 752 | } |
| 753 | + | ||
| 710 | // 关闭rtp server | 754 | // 关闭rtp server |
| 711 | - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); | ||
| 712 | - // 重新开启ssrc server | ||
| 713 | - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); | 755 | + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{ |
| 756 | + if (result) { | ||
| 757 | + // 重新开启ssrc server | ||
| 758 | + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); | ||
| 759 | + }else { | ||
| 760 | + try { | ||
| 761 | + logger.warn("[录像下载] 停止{}/{}", device.getDeviceId(), channelId); | ||
| 762 | + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null); | ||
| 763 | + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { | ||
| 764 | + logger.error("[命令发送失败] 录像下载停止, 发送BYE: {}", e.getMessage()); | ||
| 765 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); | ||
| 766 | + } | ||
| 767 | + | ||
| 768 | + dynamicTask.stop(downLoadTimeOutTaskKey); | ||
| 769 | + // 释放ssrc | ||
| 770 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | ||
| 771 | + | ||
| 772 | + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | ||
| 773 | + eventResult.msg = "下级自定义了ssrc,重新设置收流信息失败"; | ||
| 774 | + eventResult.statusCode = 500; | ||
| 775 | + errorEvent.response(eventResult); | ||
| 776 | + } | ||
| 777 | + }); | ||
| 714 | } | 778 | } |
| 715 | } | 779 | } |
| 716 | } | 780 | } |
| 717 | - | ||
| 718 | }); | 781 | }); |
| 719 | } catch (InvalidArgumentException | SipException | ParseException e) { | 782 | } catch (InvalidArgumentException | SipException | ParseException e) { |
| 720 | logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); | 783 | logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); |
web_src/src/components/dialog/recordDownload.vue
| @@ -96,7 +96,10 @@ export default { | @@ -96,7 +96,10 @@ export default { | ||
| 96 | }); | 96 | }); |
| 97 | }, | 97 | }, |
| 98 | close: function (){ | 98 | close: function (){ |
| 99 | - this.stopDownloadRecord(); | 99 | + if (this.streamInfo.progress < 1) { |
| 100 | + this.stopDownloadRecord(); | ||
| 101 | + } | ||
| 102 | + | ||
| 100 | if (this.timer !== null) { | 103 | if (this.timer !== null) { |
| 101 | window.clearTimeout(this.timer); | 104 | window.clearTimeout(this.timer); |
| 102 | this.timer = null; | 105 | this.timer = null; |