| | |
| | | import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
| | | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| | | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| | | import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | import java.math.RoundingMode; |
| | | import java.text.ParseException; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.UUID; |
| | | |
| | | @SuppressWarnings(value = {"rawtypes", "unchecked"}) |
| | |
| | | private ThreadPoolTaskExecutor taskExecutor; |
| | | |
| | | @Override |
| | | public PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, |
| | | ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, |
| | | Runnable timeoutCallback) { |
| | | public void play(MediaServerItem mediaServerItem, String deviceId, String channelId, |
| | | ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, |
| | | Runnable timeoutCallback) { |
| | | if (mediaServerItem == null) { |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm"); |
| | | } |
| | | PlayResult playResult = new PlayResult(); |
| | | RequestMessage msg = new RequestMessage(); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; |
| | | |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setKey(key); |
| | | String uuid = UUID.randomUUID().toString(); |
| | | msg.setId(uuid); |
| | | playResult.setUuid(uuid); |
| | | DeferredResult<WVPResult<StreamInfo>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); |
| | | playResult.setResult(result); |
| | | // 录像查询以channelId作为deviceId查询 |
| | | resultHolder.put(key, uuid, result); |
| | | |
| | | Device device = redisCatchStorage.getDevice(deviceId); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); |
| | | playResult.setDevice(device); |
| | | |
| | | result.onCompletion(() -> { |
| | | // 点播结束时调用截图接口 |
| | | taskExecutor.execute(() -> { |
| | | // TODO 应该在上流时调用更好,结束也可能是错误结束 |
| | | String path = "snap"; |
| | | String fileName = deviceId + "_" + channelId + ".jpg"; |
| | | WVPResult wvpResult = (WVPResult) result.getResult(); |
| | | if (Objects.requireNonNull(wvpResult).getCode() == 0) { |
| | | StreamInfo streamInfoForSuccess = (StreamInfo) wvpResult.getData(); |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId()); |
| | | String streamUrl = streamInfoForSuccess.getFmp4(); |
| | | |
| | | // 请求截图 |
| | | logger.info("[请求截图]: " + fileName); |
| | | zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName); |
| | | } |
| | | }); |
| | | }); |
| | | |
| | | if (streamInfo != null) { |
| | | String streamId = streamInfo.getStream(); |
| | |
| | | wvpResult.setMsg("点播失败, redis缓存streamId等于null"); |
| | | msg.setData(wvpResult); |
| | | resultHolder.invokeAllResult(msg); |
| | | return playResult; |
| | | return; |
| | | } |
| | | String mediaServerId = streamInfo.getMediaServerId(); |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); |
| | |
| | | msg.setData(wvpResult); |
| | | |
| | | resultHolder.invokeAllResult(msg); |
| | | return playResult; |
| | | return; |
| | | } else { |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(ErrorCode.SUCCESS.getCode()); |
| | | wvpResult.setMsg(ErrorCode.SUCCESS.getMsg()); |
| | | wvpResult.setData(streamInfo); |
| | | msg.setData(wvpResult); |
| | | |
| | | resultHolder.invokeAllResult(msg); |
| | | if (hookEvent != null) { |
| | | hookEvent.response(mediaServerItem, JSON.parseObject(JSON.toJSONString(streamInfo))); |
| | |
| | | streamId = String.format("%s_%s", device.getDeviceId(), channelId); |
| | | } |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false); |
| | | logger.info(JSONObject.toJSONString(ssrcInfo)); |
| | | if (ssrcInfo == null) { |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(ErrorCode.ERROR100.getCode()); |
| | |
| | | msg.setData(wvpResult); |
| | | |
| | | resultHolder.invokeAllResult(msg); |
| | | return playResult; |
| | | return; |
| | | } |
| | | play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response) -> { |
| | | if (hookEvent != null) { |
| | |
| | | msg.setData(wvpResult); |
| | | // 回复之前所有的点播请求 |
| | | resultHolder.invokeAllResult(msg); |
| | | }, uuid); |
| | | }); |
| | | } |
| | | return playResult; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, |
| | | ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, |
| | | InviteTimeOutCallback timeoutCallback, String uuid) { |
| | | InviteTimeOutCallback timeoutCallback) { |
| | | |
| | | logger.info("[点播开始] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); |
| | | // 超时处理 |
| | |
| | | } |
| | | } |
| | | }, userSetting.getPlayTimeout()); |
| | | //端口获取失败的ssrcInfo 没有必要发送点播指令 |
| | | if (ssrcInfo.getPort() <= 0) { |
| | | logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo); |
| | | dynamicTask.stop(timeOutTaskKey); |
| | | // 释放ssrc |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| | | |
| | | streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| | | |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + device.getDeviceId() + channelId); |
| | | msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "点播端口分配异常")); |
| | | resultHolder.invokeAllResult(msg); |
| | | return; |
| | | } |
| | | try { |
| | | cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { |
| | | logger.info("收到订阅消息: " + response.toJSONString()); |
| | | System.out.println("停止超时任务: " + timeOutTaskKey); |
| | | dynamicTask.stop(timeOutTaskKey); |
| | | |
| | | // hook响应 |
| | | onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid); |
| | | onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId); |
| | | hookEvent.response(mediaServerItemInuse, response); |
| | | logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); |
| | | String streamUrl = String.format("http://127.0.0.1:%s/%s/%s.live.flv", mediaServerItemInuse.getHttpPort(), "rtp", ssrcInfo.getStream()); |
| | | String path = "snap"; |
| | | String fileName = device.getDeviceId() + "_" + channelId + ".jpg"; |
| | | // 请求截图 |
| | | logger.info("[请求截图]: " + fileName); |
| | | zlmresTfulUtils.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName); |
| | | |
| | | }, (event) -> { |
| | | ResponseEvent responseEvent = (ResponseEvent) event.event; |
| | |
| | | logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); |
| | | dynamicTask.stop(timeOutTaskKey); |
| | | // hook响应 |
| | | onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid); |
| | | onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId); |
| | | hookEvent.response(mediaServerItemInUse, response); |
| | | }); |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) { |
| | | public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId) { |
| | | StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); |
| | | RequestMessage msg = new RequestMessage(); |
| | | if (uuid != null) { |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId); |
| | | if (streamInfo != null) { |
| | | DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); |
| | | if (deviceChannel != null) { |
| | | deviceChannel.setStreamId(streamInfo.getStream()); |
| | | storager.startPlay(deviceId, channelId, streamInfo.getStream()); |
| | | } |
| | | redisCatchStorage.startPlay(streamInfo); |
| | | |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(ErrorCode.SUCCESS.getCode()); |
| | | wvpResult.setMsg(ErrorCode.SUCCESS.getMsg()); |
| | | wvpResult.setData(streamInfo); |
| | | |
| | | msg.setData(wvpResult); |
| | | resultHolder.invokeAllResult(msg); |
| | | |
| | | } else { |
| | | logger.warn("设备预览API调用失败!"); |
| | | msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "设备预览API调用失败!")); |
| | | resultHolder.invokeAllResult(msg); |
| | | } |
| | | } |
| | | |
| | | private void onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) { |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId); |
| | | if (!ObjectUtils.isEmpty(uuid)) { |
| | | msg.setId(uuid); |
| | | } |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId); |
| | | StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); |
| | | |
| | | if (streamInfo != null) { |
| | | DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); |
| | | if (deviceChannel != null) { |
| | |
| | | |
| | | resultHolder.invokeAllResult(msg); |
| | | } else { |
| | | logger.warn("设备预览API调用失败!"); |
| | | msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "设备预览API调用失败!")); |
| | | logger.warn("录像回放调用失败!"); |
| | | msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "录像回放调用失败!")); |
| | | resultHolder.invokeAllResult(msg); |
| | | } |
| | | } |
| | |
| | | logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); |
| | | dynamicTask.stop(playBackTimeOutTaskKey); |
| | | // hook响应 |
| | | onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid); |
| | | onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid); |
| | | hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream())); |
| | | }); |
| | | } |
| | |
| | | return result; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public DeferredResult<WVPResult<StreamInfo>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) { |
| | | Device device = storager.queryVideoDevice(deviceId); |