| | |
| | | package com.genersoft.iot.vmp.service.impl; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import com.genersoft.iot.vmp.common.InviteInfo; |
| | | import com.genersoft.iot.vmp.common.InviteSessionType; |
| | | import com.genersoft.iot.vmp.conf.DynamicTask; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; |
| | | import com.genersoft.iot.vmp.gb28181.bean.*; |
| | | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| | | import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; |
| | | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
| | | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; |
| | | import com.genersoft.iot.vmp.service.IInviteStreamService; |
| | | import com.genersoft.iot.vmp.service.IMediaServerService; |
| | | import com.genersoft.iot.vmp.service.IPlatformService; |
| | | import com.genersoft.iot.vmp.service.IPlayService; |
| | |
| | | public class PlatformServiceImpl implements IPlatformService { |
| | | |
| | | private final static String REGISTER_KEY_PREFIX = "platform_register_"; |
| | | |
| | | private final static String REGISTER_FAIL_AGAIN_KEY_PREFIX = "platform_register_fail_again_"; |
| | | private final static String KEEPALIVE_KEY_PREFIX = "platform_keepalive_"; |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class); |
| | |
| | | private ParentPlatformMapper platformMapper; |
| | | |
| | | @Autowired |
| | | private PlatformCatalogMapper catalogMapper; |
| | | |
| | | @Autowired |
| | | private PlatformChannelMapper platformChannelMapper; |
| | | |
| | | @Autowired |
| | | private PlatformGbStreamMapper platformGbStreamMapper; |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Autowired |
| | | private SSRCFactory ssrcFactory; |
| | | |
| | | @Autowired |
| | | private IMediaServerService mediaServerService; |
| | |
| | | private DynamicTask dynamicTask; |
| | | |
| | | @Autowired |
| | | private ZLMRTPServerFactory zlmrtpServerFactory; |
| | | private ZLMServerFactory zlmServerFactory; |
| | | |
| | | @Autowired |
| | | private SubscribeHolder subscribeHolder; |
| | |
| | | @Autowired |
| | | private IPlayService playService; |
| | | |
| | | @Autowired |
| | | private IInviteStreamService inviteStreamService; |
| | | |
| | | |
| | | @Override |
| | |
| | | ParentPlatform parentPlatformOld = platformMapper.getParentPlatById(parentPlatform.getId()); |
| | | ParentPlatformCatch parentPlatformCatchOld = redisCatchStorage.queryPlatformCatchInfo(parentPlatformOld.getServerGBId()); |
| | | parentPlatform.setUpdateTime(DateUtil.getNow()); |
| | | if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) { |
| | | // 目录结构发生变化,清空之前的关联关系 |
| | | logger.info("保存平台{}时发现目录结构变化,清空关联关系", parentPlatform.getDeviceGBId()); |
| | | catalogMapper.delByPlatformId(parentPlatformOld.getServerGBId()); |
| | | platformChannelMapper.delByPlatformId(parentPlatformOld.getServerGBId()); |
| | | platformGbStreamMapper.delByPlatformId(parentPlatformOld.getServerGBId()); |
| | | } |
| | | |
| | | |
| | | // 停止心跳定时 |
| | | final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatformOld.getServerGBId(); |
| | |
| | | // 注销旧的 |
| | | try { |
| | | if (parentPlatformOld.isStatus()) { |
| | | logger.info("保存平台{}时发现救平台在线,发送注销命令", parentPlatform.getDeviceGBId()); |
| | | logger.info("保存平台{}时发现旧平台在线,发送注销命令", parentPlatformOld.getServerGBId()); |
| | | commanderForPlatform.unregister(parentPlatformOld, parentPlatformCatchOld.getSipTransactionInfo(), null, eventResult -> { |
| | | logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId()); |
| | | }); |
| | | } |
| | | |
| | | } catch (InvalidArgumentException | ParseException | SipException e) { |
| | | logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); |
| | | } |
| | |
| | | // 保存时启用就发送注册 |
| | | // 注册成功时由程序直接调用了online方法 |
| | | try { |
| | | logger.info("[国标级联] 平台注册 {}", parentPlatform.getDeviceGBId()); |
| | | commanderForPlatform.register(parentPlatform, eventResult -> { |
| | | logger.info("[国标级联] {},添加向上级注册失败,请确定上级平台可用时重新保存", parentPlatform.getServerGBId()); |
| | | }, null); |
| | |
| | | logger.error("[命令发送失败] 国标级联: {}", e.getMessage()); |
| | | } |
| | | } |
| | | // 重新开启定时注册, 使用续订消息 |
| | | // 重新开始心跳保活 |
| | | |
| | | |
| | | return false; |
| | | } |
| | |
| | | @Override |
| | | public void online(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo) { |
| | | logger.info("[国标级联]:{}, 平台上线", parentPlatform.getServerGBId()); |
| | | final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + parentPlatform.getServerGBId(); |
| | | dynamicTask.stop(registerFailAgainTaskKey); |
| | | |
| | | platformMapper.updateParentPlatformStatus(parentPlatform.getServerGBId(), true); |
| | | ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); |
| | | if (parentPlatformCatch == null) { |
| | |
| | | // 此时是第三次心跳超时, 平台离线 |
| | | if (platformCatch.getKeepAliveReply() == 2) { |
| | | // 设置平台离线,并重新注册 |
| | | logger.info("[国标级联] {},三次心跳超时后再次发起注册", parentPlatform.getServerGBId()); |
| | | try { |
| | | commanderForPlatform.register(parentPlatform, eventResult1 -> { |
| | | logger.info("[国标级联] {},三次心跳超时后再次发起注册仍然失败,开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId()); |
| | | offline(parentPlatform, false); |
| | | }, null); |
| | | } catch (InvalidArgumentException | ParseException | SipException e) { |
| | | logger.error("[命令发送失败] 国标级联 注册: {}", e.getMessage()); |
| | | } |
| | | logger.info("[国标级联] 三次心跳超时, 平台{}({})离线", parentPlatform.getName(), parentPlatform.getServerGBId()); |
| | | offline(parentPlatform, false); |
| | | |
| | | } |
| | | |
| | | }else { |
| | |
| | | // 心跳成功 |
| | | // 清空之前的心跳超时计数 |
| | | ParentPlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); |
| | | if (platformCatch.getKeepAliveReply() > 0) { |
| | | if (platformCatch != null && platformCatch.getKeepAliveReply() > 0) { |
| | | platformCatch.setKeepAliveReply(0); |
| | | redisCatchStorage.updatePlatformCatchInfo(platformCatch); |
| | | } |
| | |
| | | |
| | | private void registerTask(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo){ |
| | | try { |
| | | // 设置超时重发, 后续从底层支持消息重发 |
| | | String key = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId() + "_timeout"; |
| | | if (dynamicTask.isAlive(key)) { |
| | | return; |
| | | // 不在同一个会话中续订则每次全新注册 |
| | | if (!userSetting.isRegisterKeepIntDialog()) { |
| | | sipTransactionInfo = null; |
| | | } |
| | | dynamicTask.startDelay(key, ()->{ |
| | | registerTask(parentPlatform, sipTransactionInfo); |
| | | }, 1000); |
| | | logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId()); |
| | | |
| | | if (sipTransactionInfo == null) { |
| | | logger.info("[国标级联] 平台:{}注册即将到期,开始重新注册", parentPlatform.getServerGBId()); |
| | | }else { |
| | | logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId()); |
| | | } |
| | | |
| | | commanderForPlatform.register(parentPlatform, sipTransactionInfo, eventResult -> { |
| | | dynamicTask.stop(key); |
| | | logger.info("[国标级联] 平台:{}注册失败,{}:{}", parentPlatform.getServerGBId(), |
| | | eventResult.statusCode, eventResult.msg); |
| | | offline(parentPlatform, false); |
| | | },eventResult -> { |
| | | dynamicTask.stop(key); |
| | | }); |
| | | }, null); |
| | | } catch (InvalidArgumentException | ParseException | SipException e) { |
| | | logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage()); |
| | | } |
| | |
| | | // 停止所有推流 |
| | | logger.info("[平台离线] {}, 停止所有推流", parentPlatform.getServerGBId()); |
| | | stopAllPush(parentPlatform.getServerGBId()); |
| | | if (stopRegister) { |
| | | // 清除注册定时 |
| | | logger.info("[平台离线] {}, 停止定时注册任务", parentPlatform.getServerGBId()); |
| | | final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId(); |
| | | if (dynamicTask.contains(registerTaskKey)) { |
| | | dynamicTask.stop(registerTaskKey); |
| | | } |
| | | |
| | | // 清除注册定时 |
| | | logger.info("[平台离线] {}, 停止定时注册任务", parentPlatform.getServerGBId()); |
| | | final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId(); |
| | | if (dynamicTask.contains(registerTaskKey)) { |
| | | dynamicTask.stop(registerTaskKey); |
| | | } |
| | | // 清除心跳定时 |
| | | logger.info("[平台离线] {}, 停止定时发送心跳任务", parentPlatform.getServerGBId()); |
| | | final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId(); |
| | | if (dynamicTask.contains(keepaliveTaskKey)) { |
| | | // 添加心跳任务 |
| | | // 清除心跳任务 |
| | | dynamicTask.stop(keepaliveTaskKey); |
| | | } |
| | | // 停止目录订阅回复 |
| | | logger.info("[平台离线] {}, 停止订阅回复", parentPlatform.getServerGBId()); |
| | | subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId()); |
| | | // 发起定时自动重新注册 |
| | | if (!stopRegister) { |
| | | // 设置为60秒自动尝试重新注册 |
| | | final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + parentPlatform.getServerGBId(); |
| | | ParentPlatform platform = platformMapper.getParentPlatById(parentPlatform.getId()); |
| | | if (platform.isEnable()) { |
| | | dynamicTask.startCron(registerFailAgainTaskKey, |
| | | ()-> registerTask(platform, null), |
| | | userSetting.getRegisterAgainAfterTime() * 1000); |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | | private void stopAllPush(String platformId) { |
| | | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServer(platformId); |
| | | if (sendRtpItems != null && sendRtpItems.size() > 0) { |
| | | for (SendRtpItem sendRtpItem : sendRtpItems) { |
| | | ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc()); |
| | | redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), null, null); |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | Map<String, Object> param = new HashMap<>(3); |
| | | param.put("vhost", "__defaultVhost__"); |
| | | param.put("app", sendRtpItem.getApp()); |
| | | param.put("stream", sendRtpItem.getStream()); |
| | | zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); |
| | | zlmServerFactory.stopSendRtpStream(mediaInfo, param); |
| | | } |
| | | } |
| | | } |
| | |
| | | logger.info("[国标级联] 语音喊话未找到可用的zlm. platform: {}", platform.getServerGBId()); |
| | | return; |
| | | } |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(platform.getServerGBId(), channelId); |
| | | if (streamInfo != null) { |
| | | InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, platform.getServerGBId(), channelId); |
| | | |
| | | if (inviteInfo != null && inviteInfo.getStreamInfo() != null) { |
| | | // 如果zlm不存在这个流,则删除数据即可 |
| | | MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(streamInfo.getMediaServerId()); |
| | | MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId()); |
| | | if (mediaServerItemForStreamInfo != null) { |
| | | Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItemForStreamInfo, streamInfo.getApp(), streamInfo.getStream()); |
| | | Boolean ready = zlmServerFactory.isStreamReady(mediaServerItemForStreamInfo, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream()); |
| | | if (!ready) { |
| | | // 错误存在于redis中的数据 |
| | | redisCatchStorage.stopPlay(streamInfo); |
| | | inviteStreamService.removeInviteInfo(inviteInfo); |
| | | }else { |
| | | // 流确实尚在推流,直接回调结果 |
| | | JSONObject json = new JSONObject(); |
| | | json.put("app", streamInfo.getApp()); |
| | | json.put("stream", streamInfo.getStream()); |
| | | hookEvent.response(mediaServerItemForStreamInfo, json); |
| | | OnStreamChangedHookParam hookParam = new OnStreamChangedHookParam(); |
| | | hookParam.setApp(inviteInfo.getStreamInfo().getApp()); |
| | | hookParam.setStream(inviteInfo.getStreamInfo().getStream()); |
| | | |
| | | hookEvent.response(mediaServerItemForStreamInfo, hookParam); |
| | | return; |
| | | } |
| | | } |
| | |
| | | } |
| | | // 默认不进行SSRC校验, TODO 后续可改为配置 |
| | | boolean ssrcCheck = false; |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, ssrcCheck, false, null, true); |
| | | int tcpMode; |
| | | if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-PASSIVE")) { |
| | | tcpMode = 1; |
| | | }else if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) { |
| | | tcpMode = 2; |
| | | } else { |
| | | tcpMode = 0; |
| | | } |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, ssrcCheck, false, null, true, false, tcpMode); |
| | | if (ssrcInfo == null || ssrcInfo.getPort() < 0) { |
| | | logger.info("[国标级联] 发起语音喊话 开启端口监听失败, platform: {}, channel: {}", platform.getServerGBId(), channelId); |
| | | errorEvent.response(new SipSubscribe.EventResult(-1, "端口监听失败")); |
| | | SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>(); |
| | | eventResult.statusCode = -1; |
| | | eventResult.msg = "端口监听失败"; |
| | | eventResult.type = SipSubscribe.EventResultType.failedToGetPort; |
| | | errorEvent.response(eventResult); |
| | | return; |
| | | } |
| | | logger.info("[国标级联] 语音喊话,发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", |
| | |
| | | String timeOutTaskKey = UUID.randomUUID().toString(); |
| | | dynamicTask.startDelay(timeOutTaskKey, () -> { |
| | | // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况 |
| | | if (redisCatchStorage.queryPlayByDevice(platform.getServerGBId(), channelId) == null) { |
| | | InviteInfo inviteInfoForBroadcast = inviteStreamService.getInviteInfo(InviteSessionType.BROADCAST, platform.getServerGBId(), channelId, null); |
| | | if (inviteInfoForBroadcast == null) { |
| | | logger.info("[国标级联] 发起语音喊话 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", platform.getServerGBId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc()); |
| | | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| | | try { |
| | |
| | | } |
| | | } |
| | | }, userSetting.getPlayTimeout()); |
| | | commanderForPlatform.broadcastInviteCmd(platform, channelId, mediaServerItem, ssrcInfo, (mediaServerItemForInvite, response)->{ |
| | | commanderForPlatform.broadcastInviteCmd(platform, channelId, mediaServerItem, ssrcInfo, (mediaServerItemForInvite, hookParam)->{ |
| | | logger.info("[国标级联] 发起语音喊话 收到上级推流 deviceId: {}, channelId: {}", platform.getServerGBId(), channelId); |
| | | dynamicTask.stop(timeOutTaskKey); |
| | | // hook响应 |
| | | playService.onPublishHandlerForPlay(mediaServerItemForInvite, response, platform.getServerGBId(), channelId); |
| | | playService.onPublishHandlerForPlay(mediaServerItemForInvite, hookParam, platform.getServerGBId(), channelId); |
| | | // 收到流 |
| | | if (hookEvent != null) { |
| | | hookEvent.response(mediaServerItem, response); |
| | | hookEvent.response(mediaServerItem, hookParam); |
| | | } |
| | | }, event -> { |
| | | // 收到200OK 检测ssrc是否有变化,防止上级自定义了ssrc |
| | |
| | | logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse); |
| | | if (!mediaServerItem.isRtpEnable()) { |
| | | logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); |
| | | |
| | | if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) { |
| | | // ssrc 不可用 |
| | | // 释放ssrc |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| | | streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream()); |
| | | event.msg = "下级自定义了ssrc,但是此ssrc不可用"; |
| | | event.statusCode = 400; |
| | | errorEvent.response(event); |
| | | return; |
| | | } |
| | | |
| | | // 释放ssrc |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| | | // 单端口模式streamId也有变化,需要重新设置监听 |
| | | if (!mediaServerItem.isRtpEnable()) { |
| | | // 添加订阅 |
| | | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); |
| | | subscribe.removeSubscribe(hookSubscribe); |
| | | hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); |
| | | subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> { |
| | | logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); |
| | | subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { |
| | | logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam); |
| | | dynamicTask.stop(timeOutTaskKey); |
| | | // hook响应 |
| | | playService.onPublishHandlerForPlay(mediaServerItemInUse, response, platform.getServerGBId(), channelId); |
| | | hookEvent.response(mediaServerItemInUse, response); |
| | | playService.onPublishHandlerForPlay(mediaServerItemInUse, hookParam, platform.getServerGBId(), channelId); |
| | | hookEvent.response(mediaServerItemInUse, hookParam); |
| | | }); |
| | | } |
| | | // 关闭rtp server |
| | | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); |
| | | // 重新开启ssrc server |
| | | mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, false, false, ssrcInfo.getPort(), true); |
| | | |
| | | |
| | | mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, false, false, ssrcInfo.getPort(), true, false, tcpMode); |
| | | } |
| | | } |
| | | }, eventResult -> { |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void stopBroadcast(ParentPlatform platform, String channelId, String stream) throws InvalidArgumentException, ParseException, SsrcTransactionNotFoundException, SipException { |
| | | commanderForPlatform.streamByeCmd(platform, channelId, stream, null, null); |
| | | public void stopBroadcast(ParentPlatform platform, DeviceChannel channel, String stream, boolean sendBye, MediaServerItem mediaServerItem) { |
| | | |
| | | try { |
| | | if (sendBye) { |
| | | commanderForPlatform.streamByeCmd(platform, channel.getChannelId(), stream, null, null); |
| | | } |
| | | } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { |
| | | logger.warn("[消息发送失败] 停止语音对讲, 平台:{},通道:{}", platform.getId(), channel.getChannelId() ); |
| | | } finally { |
| | | mediaServerService.closeRTPServer(mediaServerItem, stream); |
| | | InviteInfo inviteInfo = inviteStreamService.getInviteInfo(null, platform.getServerGBId(), channel.getChannelId(), stream); |
| | | if (inviteInfo != null) { |
| | | // 释放ssrc |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), inviteInfo.getSsrcInfo().getSsrc()); |
| | | inviteStreamService.removeInviteInfo(inviteInfo); |
| | | } |
| | | streamSession.remove(platform.getServerGBId(), channel.getChannelId(), stream); |
| | | } |
| | | } |
| | | } |