| | |
| | | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.*;
|
| | | import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
| | | import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
| | | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
|
| | | import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
| | | import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
| | | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
| | |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
| | | import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
|
| | | import com.genersoft.iot.vmp.service.*;
|
| | | import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
| | | import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
| | | import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService;
|
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
| | | import com.genersoft.iot.vmp.utils.DateUtil;
|
| | |
| | | private AudioBroadcastManager audioBroadcastManager;
|
| | |
|
| | | @Autowired
|
| | | private ZLMServerFactory zlmServerFactory;
|
| | |
|
| | | @Autowired
|
| | | private IPlayService playService;
|
| | |
|
| | | @Autowired
|
| | |
| | |
|
| | | @Autowired
|
| | | private IRedisCatchStorage redisCatchStorage;
|
| | |
|
| | |
|
| | | @Autowired
|
| | | private IRedisRpcService redisRpcService;
|
| | |
|
| | | @Autowired
|
| | | private IInviteStreamService inviteStreamService;
|
| | |
| | | private EventPublisher eventPublisher;
|
| | |
|
| | | @Autowired
|
| | | private ZLMMediaListManager zlmMediaListManager;
|
| | |
|
| | | @Autowired
|
| | | private ZlmHttpHookSubscribe subscribe;
|
| | |
|
| | | @Autowired
|
| | |
| | | private VideoStreamSessionManager sessionManager;
|
| | |
|
| | | @Autowired
|
| | | private AssistRESTfulUtils assistRESTfulUtils;
|
| | |
|
| | | @Autowired
|
| | | private SSRCFactory ssrcFactory;
|
| | |
|
| | | @Qualifier("taskExecutor")
|
| | |
| | |
|
| | | @Autowired
|
| | | private RedisTemplate<Object, Object> redisTemplate;
|
| | |
|
| | | @Autowired
|
| | | private IStreamPushService streamPushService;
|
| | |
|
| | | /**
|
| | | * 服务器定时上报时间,上报间隔可配置,默认10s上报一次
|
| | |
| | |
|
| | | taskExecutor.execute(() -> {
|
| | | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
|
| | | if (subscribes != null && subscribes.size() > 0) {
|
| | | if (subscribes != null && !subscribes.isEmpty()) {
|
| | | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
| | | subscribe.response(null, param);
|
| | | }
|
| | |
| | | @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
|
| | | public HookResult onPlay(@RequestBody OnPlayHookParam param) {
|
| | | if (logger.isDebugEnabled()) {
|
| | | logger.debug("[ZLM HOOK] 播放鉴权:{}->{}" + param.getMediaServerId(), param);
|
| | | logger.debug("[ZLM HOOK] 播放鉴权:{}->{}", param.getMediaServerId(), param);
|
| | | }
|
| | | String mediaServerId = param.getMediaServerId();
|
| | |
|
| | |
| | | // 鉴权通过
|
| | | redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
|
| | | }
|
| | | } else {
|
| | | zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId());
|
| | | }
|
| | |
|
| | |
|
| | | HookResultForOnPublish result = HookResultForOnPublish.SUCCESS();
|
| | | result.setEnable_audio(true);
|
| | | taskExecutor.execute(() -> {
|
| | | ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
|
| | | if (subscribe != null) {
|
| | | if (mediaInfo != null) {
|
| | | subscribe.response(mediaInfo, param);
|
| | | } else {
|
| | | new HookResultForOnPublish(1, "zlm not register");
|
| | | }
|
| | | subscribe.response(mediaInfo, param);
|
| | | }
|
| | | });
|
| | |
|
| | |
| | | if ("rtp".equals(param.getApp())) {
|
| | |
|
| | | InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
|
| | |
|
| | | // 单端口模式下修改流 ID
|
| | | if (!mediaInfo.isRtpEnable() && inviteInfo == null) {
|
| | | String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));
|
| | |
| | | if (inviteInfo != null) {
|
| | | result.setStream_replace(inviteInfo.getStream());
|
| | | logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream());
|
| | | // 单端口模式下修改流ID为目标流ID,不然其他地方可能都无法对应
|
| | | param.setStream(inviteInfo.getStream());
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | || param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|
| | | || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
|
| | | param.setSeverId(userSetting.getServerId());
|
| | | zlmMediaListManager.addPush(param);
|
| | |
|
| | | streamPushService.updatePush(param);
|
| | | // 冗余数据,自己系统中自用
|
| | | redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param);
|
| | | }
|
| | |
| | | }
|
| | | }
|
| | | GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
|
| | | if (gbStream != null) {
|
| | | // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
|
| | | // 查找是否关联了国标, 关联了不删除, 置为离线
|
| | | if (gbStream == null) {
|
| | | storager.removeMedia(param.getApp(), param.getStream());
|
| | | }else {
|
| | | // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
|
| | | storager.mediaOffline(param.getApp(), param.getStream());
|
| | | }
|
| | | zlmMediaListManager.removeMedia(param.getApp(), param.getStream());
|
| | | }
|
| | | GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
|
| | | if (gbStream != null) {
|
| | |
| | | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());
|
| | | if (!sendRtpItems.isEmpty()) {
|
| | | for (SendRtpItem sendRtpItem : sendRtpItems) {
|
| | | if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) {
|
| | | String platformId = sendRtpItem.getPlatformId();
|
| | | ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
|
| | | Device device = deviceService.getDevice(platformId);
|
| | |
|
| | | if (sendRtpItem == null) {
|
| | | continue;
|
| | | }
|
| | | if (sendRtpItem.getApp().equals(param.getApp())) {
|
| | | // 在hook收到这个消息,说明发流一定是本级完成的。
|
| | | redisCatchStorage.deleteSendRTPServer(sendRtpItem);
|
| | | ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
|
| | | ParentPlatform platform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
|
| | | Device device = deviceService.getDevice(sendRtpItem.getPlatformId());
|
| | | try {
|
| | | if (platform != null) {
|
| | | commanderFroPlatform.streamByeCmd(platform, sendRtpItem);
|
| | | redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(),
|
| | | sendRtpItem.getCallId(), sendRtpItem.getStream());
|
| | | } else {
|
| | | redisCatchStorage.sendPlatformStopPlayMsg(sendRtpItem, platform);
|
| | | } else if (device != null) {
|
| | | cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId());
|
| | | if (sendRtpItem.getPlayType().equals(InviteStreamType.BROADCAST)
|
| | | || sendRtpItem.getPlayType().equals(InviteStreamType.TALK)) {
|
| | |
| | | audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
| | | }
|
| | | }
|
| | | }else {
|
| | | // 通知其他wvp停止发流
|
| | | redisRpcService.rtpSendStopped(sendRtpItem.getRedisKey());
|
| | | }
|
| | | } catch (SipException | InvalidArgumentException | ParseException |
|
| | | SsrcTransactionNotFoundException e) {
|
| | |
| | | } catch (SipException | InvalidArgumentException | ParseException e) {
|
| | | logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
|
| | | }
|
| | | redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
|
| | | sendRtpItem.getCallId(), sendRtpItem.getStream());
|
| | | redisCatchStorage.deleteSendRTPServer(sendRtpItem);
|
| | | ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
|
| | | if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) {
|
| | | MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
|
| | | sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
|
| | | sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId());
|
| | | messageForPushChannel.setPlatFormIndex(parentPlatform.getId());
|
| | | redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel);
|
| | | redisCatchStorage.sendPlatformStopPlayMsg(sendRtpItem, parentPlatform);
|
| | | }
|
| | | }
|
| | | }
|
| | |
| | | logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId());
|
| | | taskExecutor.execute(() -> {
|
| | | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
|
| | | if (subscribes != null && subscribes.size() > 0) {
|
| | | if (subscribes != null && !subscribes.isEmpty()) {
|
| | | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
| | | subscribe.response(null, zlmServerConfig);
|
| | | }
|
| | |
| | | }
|
| | | taskExecutor.execute(() -> {
|
| | | List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());
|
| | | if (sendRtpItems.size() > 0) {
|
| | | if (!sendRtpItems.isEmpty()) {
|
| | | for (SendRtpItem sendRtpItem : sendRtpItems) {
|
| | | ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
|
| | | ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
|
| | | try {
|
| | | commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
|
| | | } catch (SipException | InvalidArgumentException | ParseException e) {
|
| | | logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
|
| | | if(parentPlatform != null) {
|
| | | try {
|
| | | commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
|
| | | } catch (SipException | InvalidArgumentException | ParseException e) {
|
| | | logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
|
| | | }
|
| | | }
|
| | | redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
|
| | | sendRtpItem.getCallId(), sendRtpItem.getStream());
|
| | | ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
|
| | | redisCatchStorage.deleteSendRTPServer(sendRtpItem);
|
| | | }
|
| | | }
|
| | | });
|
| | |
| | | */
|
| | | @ResponseBody
|
| | | @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8")
|
| | | public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam
|
| | | public HookResult onRtpServerTimeout(@RequestBody OnRtpServerTimeoutHookParam
|
| | | param) {
|
| | | logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc());
|
| | |
|
| | | taskExecutor.execute(() -> {
|
| | | JSONObject json = (JSONObject) JSON.toJSON(param);
|
| | | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);
|
| | | if (subscribes != null && !subscribes.isEmpty()) {
|
| | | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|