优化点播, 级联点播级联录像。级联列表显示订阅状态
| | |
| | | |
| | | // 取消订阅 |
| | | sipCommanderForPlatform.unregister(parentPlatform, null, (eventResult)->{ |
| | | ParentPlatform platform = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId()); |
| | | sipCommanderForPlatform.register(platform, null, null); |
| | | // 发送平台未注册消息 |
| | | publisher.platformNotRegisterEventPublish(parentPlatform.getServerGBId()); |
| | | }); |
| | | |
| | | // 发送平台未注册消息 |
| | | publisher.platformNotRegisterEventPublish(parentPlatform.getServerGBId()); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.gb28181.bean; |
| | | |
| | | public interface InviteStreamCallback { |
| | | void call(InviteStreamInfo inviteStreamInfo); |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.gb28181.bean; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | |
| | | public class InviteStreamInfo { |
| | | |
| | | public InviteStreamInfo(MediaServerItem mediaServerItem, JSONObject response, String callId, String app, String stream) { |
| | | this.mediaServerItem = mediaServerItem; |
| | | this.response = response; |
| | | this.callId = callId; |
| | | this.app = app; |
| | | this.stream = stream; |
| | | } |
| | | |
| | | private MediaServerItem mediaServerItem; |
| | | private JSONObject response; |
| | | private String callId; |
| | | private String app; |
| | | private String stream; |
| | | |
| | | public MediaServerItem getMediaServerItem() { |
| | | return mediaServerItem; |
| | | } |
| | | |
| | | public void setMediaServerItem(MediaServerItem mediaServerItem) { |
| | | this.mediaServerItem = mediaServerItem; |
| | | } |
| | | |
| | | public JSONObject getResponse() { |
| | | return response; |
| | | } |
| | | |
| | | public void setResponse(JSONObject response) { |
| | | this.response = response; |
| | | } |
| | | |
| | | public String getCallId() { |
| | | return callId; |
| | | } |
| | | |
| | | public void setCallId(String callId) { |
| | | this.callId = callId; |
| | | } |
| | | |
| | | public String getApp() { |
| | | return app; |
| | | } |
| | | |
| | | public void setApp(String app) { |
| | | this.app = app; |
| | | } |
| | | |
| | | public String getStream() { |
| | | return stream; |
| | | } |
| | | |
| | | public void setStream(String stream) { |
| | | this.stream = stream; |
| | | } |
| | | } |
| | |
| | | */ |
| | | private String catalogId; |
| | | |
| | | /** |
| | | * 已被订阅目录信息 |
| | | */ |
| | | private boolean catalogSubscribe; |
| | | |
| | | /** |
| | | * 已被订阅报警信息 |
| | | */ |
| | | private boolean alarmSubscribe; |
| | | |
| | | /** |
| | | * 已被订阅GPS信息 |
| | | */ |
| | | private boolean gpsSubscribe; |
| | | |
| | | public Integer getId() { |
| | | return id; |
| | | } |
| | |
| | | public void setCatalogId(String catalogId) { |
| | | this.catalogId = catalogId; |
| | | } |
| | | |
| | | public boolean isCatalogSubscribe() { |
| | | return catalogSubscribe; |
| | | } |
| | | |
| | | public void setCatalogSubscribe(boolean catalogSubscribe) { |
| | | this.catalogSubscribe = catalogSubscribe; |
| | | } |
| | | |
| | | public boolean isAlarmSubscribe() { |
| | | return alarmSubscribe; |
| | | } |
| | | |
| | | public void setAlarmSubscribe(boolean alarmSubscribe) { |
| | | this.alarmSubscribe = alarmSubscribe; |
| | | } |
| | | |
| | | public boolean isGpsSubscribe() { |
| | | return gpsSubscribe; |
| | | } |
| | | |
| | | public void setGpsSubscribe(boolean gpsSubscribe) { |
| | | this.gpsSubscribe = gpsSubscribe; |
| | | } |
| | | } |
| | |
| | | this.eventType = eventHeader.getEventType(); |
| | | this.transaction = evt.getServerTransaction(); |
| | | this.dialog = evt.getDialog(); |
| | | CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); |
| | | this.callId = callIdHeader.getCallId(); |
| | | } |
| | | |
| | | private String id; |
| | |
| | | errorTimeSubscribes.remove(key); |
| | | } |
| | | } |
| | | logger.info("okTimeSubscribes.size:{}",okTimeSubscribes.size()); |
| | | logger.info("okSubscribes.size:{}",okSubscribes.size()); |
| | | logger.info("errorTimeSubscribes.size:{}",errorTimeSubscribes.size()); |
| | | logger.info("errorSubscribes.size:{}",errorSubscribes.size()); |
| | | logger.debug("okTimeSubscribes.size:{}",okTimeSubscribes.size()); |
| | | logger.debug("okSubscribes.size:{}",okSubscribes.size()); |
| | | logger.debug("errorTimeSubscribes.size:{}",errorTimeSubscribes.size()); |
| | | logger.debug("errorSubscribes.size:{}",errorSubscribes.size()); |
| | | } |
| | | |
| | | public interface Event { |
| | |
| | | List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId); |
| | | if (parentPlatforms != null && parentPlatforms.size() > 0) { |
| | | for (ParentPlatform platform : parentPlatforms) { |
| | | String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + platform.getServerGBId(); |
| | | // SubscribeInfo subscribeInfo = redisCatchStorage.getSubscribe(key); |
| | | SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId()); |
| | | if (subscribeInfo == null) continue; |
| | | logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); |
| | |
| | | logger.debug("\n收到响应:\n{}", responseEvent.getResponse()); |
| | | int status = response.getStatusCode(); |
| | | |
| | | if (((status >= 200) && (status < 300)) || status == 401) { // Success! |
| | | if (((status >= 200) && (status < 300)) || status == Response.UNAUTHORIZED) { // Success! |
| | | CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME); |
| | | String method = cseqHeader.getMethod(); |
| | | ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method); |
| | | if (sipRequestProcessor != null) { |
| | | sipRequestProcessor.process(responseEvent); |
| | | } |
| | | if (responseEvent.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) { |
| | | if (status != Response.UNAUTHORIZED && responseEvent.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) { |
| | | CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME); |
| | | if (callIdHeader != null) { |
| | | SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId()); |
| | |
| | |
|
| | | import com.genersoft.iot.vmp.common.StreamInfo;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.Device;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
|
| | | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
| | | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
| | |
| | | * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
|
| | | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
| | | */
|
| | | void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
| | | void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event errorEvent);
|
| | |
|
| | | /**
|
| | | * 请求历史媒体下载
|
| | |
| | | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
| | | * @param downloadSpeed 下载倍速参数
|
| | | */
|
| | | void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
|
| | | void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event, SipSubscribe.Event errorEvent);
|
| | |
|
| | | /**
|
| | | * 视频流停止
|
| | | */
|
| | | void streamByeCmd(String deviceId, String channelId, String stream, SipSubscribe.Event okEvent);
|
| | | void streamByeCmd(String deviceId, String channelId, String stream);
|
| | | void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent);
|
| | | void streamByeCmd(String deviceId, String channelId, String stream, String callId);
|
| | |
|
| | | /**
|
| | | * 回放暂停
|
| | |
| | | import com.genersoft.iot.vmp.conf.SipConfig;
|
| | | import com.genersoft.iot.vmp.conf.UserSetup;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.Device;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
|
| | | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
| | | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
| | |
| | | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
| | | */
|
| | | @Override
|
| | | public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
|
| | | , SipSubscribe.Event errorEvent) {
|
| | | public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
| | | String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
|
| | | SipSubscribe.Event errorEvent) {
|
| | | try {
|
| | |
|
| | | logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
| | |
|
| | | // 添加订阅
|
| | | JSONObject subscribeKey = new JSONObject();
|
| | | subscribeKey.put("app", "rtp");
|
| | | subscribeKey.put("stream", ssrcInfo.getStream());
|
| | | subscribeKey.put("regist", true);
|
| | | subscribeKey.put("schema", "rtmp");
|
| | | subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
| | | logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
|
| | | subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
| | | (MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
| | | if (event != null) {
|
| | | event.response(mediaServerItemInUse, json);
|
| | | }
|
| | | });
|
| | |
|
| | | StringBuffer content = new StringBuffer(200);
|
| | | content.append("v=0\r\n");
|
| | |
| | | CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
|
| | | : udpSipProvider.getNewCallId();
|
| | |
|
| | | // 添加订阅
|
| | | JSONObject subscribeKey = new JSONObject();
|
| | | subscribeKey.put("app", "rtp");
|
| | | subscribeKey.put("stream", ssrcInfo.getStream());
|
| | | subscribeKey.put("regist", true);
|
| | | subscribeKey.put("schema", "rtmp");
|
| | | subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
| | | logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey);
|
| | | subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
| | | (MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
| | | if (hookEvent != null) {
|
| | | InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream());
|
| | | hookEvent.call(inviteStreamInfo);
|
| | | }
|
| | | });
|
| | | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
|
| | |
|
| | | transmitRequest(device, request, errorEvent, okEvent -> {
|
| | |
| | | streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction());
|
| | | streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
|
| | | });
|
| | | if (inviteStreamCallback != null) {
|
| | | inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
|
| | | }
|
| | | } catch ( SipException | ParseException | InvalidArgumentException e) {
|
| | | e.printStackTrace();
|
| | | }
|
| | |
| | | * @param downloadSpeed 下载倍速参数
|
| | | */
|
| | | @Override
|
| | | public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event
|
| | | public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event
|
| | | , SipSubscribe.Event errorEvent) {
|
| | | try {
|
| | | logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
| | |
|
| | | // 添加订阅
|
| | | JSONObject subscribeKey = new JSONObject();
|
| | | subscribeKey.put("app", "rtp");
|
| | | subscribeKey.put("stream", ssrcInfo.getStream());
|
| | | subscribeKey.put("regist", true);
|
| | | subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
| | | logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
|
| | | subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
| | | (MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
| | | event.response(mediaServerItemInUse, json);
|
| | | subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
| | | });
|
| | |
|
| | | StringBuffer content = new StringBuffer(200);
|
| | | content.append("v=0\r\n");
|
| | |
| | | CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
|
| | | : udpSipProvider.getNewCallId();
|
| | |
|
| | | // 添加订阅
|
| | | JSONObject subscribeKey = new JSONObject();
|
| | | subscribeKey.put("app", "rtp");
|
| | | subscribeKey.put("stream", ssrcInfo.getStream());
|
| | | subscribeKey.put("regist", true);
|
| | | subscribeKey.put("mediaServerId", mediaServerItem.getId());
|
| | | logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
|
| | | subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
| | | (MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
| | | event.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
|
| | | subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
| | | });
|
| | |
|
| | | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
|
| | |
|
| | | ClientTransaction transaction = transmitRequest(device, request, errorEvent);
|
| | |
| | | * 视频流停止, 不使用回调
|
| | | */
|
| | | @Override
|
| | | public void streamByeCmd(String deviceId, String channelId, String stream) {
|
| | | streamByeCmd(deviceId, channelId, stream, null);
|
| | | public void streamByeCmd(String deviceId, String channelId, String stream, String callId) {
|
| | | streamByeCmd(deviceId, channelId, stream, callId, null);
|
| | | }
|
| | |
|
| | | /**
|
| | | * 视频流停止
|
| | | */
|
| | | @Override
|
| | | public void streamByeCmd(String deviceId, String channelId, String stream, SipSubscribe.Event okEvent) {
|
| | | public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) {
|
| | | try {
|
| | | SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream);
|
| | | ClientTransaction transaction = streamSession.getTransactionByStream(deviceId, channelId, stream);
|
| | |
| | | }
|
| | | return;
|
| | | }
|
| | | SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, stream);
|
| | | SIPDialog dialog;
|
| | | if (callId != null) {
|
| | | dialog = streamSession.getDialogByCallId(deviceId, channelId, callId);
|
| | | }else {
|
| | | if (stream == null) return;
|
| | | dialog = streamSession.getDialogByStream(deviceId, channelId, stream);
|
| | | }
|
| | |
|
| | |
|
| | | if (dialog == null) {
|
| | | logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId);
|
| | | return;
|
| | |
| | | import com.genersoft.iot.vmp.utils.SerializeUtils; |
| | | import gov.nist.javax.sip.SipProviderImpl; |
| | | import gov.nist.javax.sip.SipStackImpl; |
| | | import gov.nist.javax.sip.message.MessageFactoryImpl; |
| | | import gov.nist.javax.sip.message.SIPRequest; |
| | | import gov.nist.javax.sip.stack.SIPDialog; |
| | | import org.slf4j.Logger; |
| | |
| | | @Override |
| | | public boolean unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) { |
| | | ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); |
| | | parentPlatform.setExpires("0"); |
| | | if (parentPlatformCatch != null) { |
| | | parentPlatformCatch.setParentPlatform(parentPlatform); |
| | | redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); |
| | | } |
| | | parentPlatform.setExpires("0"); |
| | | return register(parentPlatform, null, null, errorEvent, okEvent, false); |
| | | } |
| | | |
| | |
| | | private void sendNotify(ParentPlatform parentPlatform, String catalogXmlContent, |
| | | SubscribeInfo subscribeInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent ) |
| | | throws NoSuchFieldException, IllegalAccessException, SipException, ParseException { |
| | | MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory(); |
| | | // 设置编码, 防止中文乱码 |
| | | messageFactory.setDefaultContentEncodingCharset("gb2312"); |
| | | Dialog dialog = subscribeInfo.getDialog(); |
| | | Request notifyRequest = dialog.createRequest(Request.NOTIFY); |
| | | |
| | | if (dialog == null) return; |
| | | SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY); |
| | | ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); |
| | | |
| | | notifyRequest.setContent(catalogXmlContent, contentTypeHeader); |
| | | |
| | | SubscriptionStateHeader subscriptionState = sipFactory.createHeaderFactory() |
| | |
| | | } |
| | | |
| | | @Override |
| | | public boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) { |
| | | public boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, |
| | | SubscribeInfo subscribeInfo, Integer index) { |
| | | if (parentPlatform == null |
| | | || deviceChannels == null |
| | | || deviceChannels.size() == 0 |
| | |
| | | recordXml.append("<SN>" +recordInfo.getSn() + "</SN>\r\n"); |
| | | recordXml.append("<DeviceID>" + recordInfo.getDeviceId() + "</DeviceID>\r\n"); |
| | | recordXml.append("<SumNum>" + recordInfo.getSumNum() + "</SumNum>\r\n"); |
| | | recordXml.append("<RecordList Num=\"" + recordInfo.getRecordList().size()+"\">\r\n"); |
| | | for (RecordItem recordItem : recordInfo.getRecordList()) { |
| | | recordXml.append("<Item>\r\n"); |
| | | if (deviceChannel != null) { |
| | | recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n"); |
| | | recordXml.append("<Name>" + recordItem.getName() + "</Name>\r\n"); |
| | | recordXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n"); |
| | | recordXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n"); |
| | | recordXml.append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n"); |
| | | recordXml.append("<Type>" + recordItem.getType() + "</Type>\r\n"); |
| | | if (!StringUtils.isEmpty(recordItem.getFileSize())) { |
| | | recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n"); |
| | | } |
| | | if (!StringUtils.isEmpty(recordItem.getFilePath())) { |
| | | recordXml.append("<FilePath>" + recordItem.getFilePath() + "</FilePath>\r\n"); |
| | | if (recordInfo.getRecordList() == null ) { |
| | | recordXml.append("<RecordList Num=\"0\">\r\n"); |
| | | }else { |
| | | recordXml.append("<RecordList Num=\"" + recordInfo.getRecordList().size()+"\">\r\n"); |
| | | if (recordInfo.getRecordList().size() > 0) { |
| | | for (RecordItem recordItem : recordInfo.getRecordList()) { |
| | | recordXml.append("<Item>\r\n"); |
| | | if (deviceChannel != null) { |
| | | recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n"); |
| | | recordXml.append("<Name>" + recordItem.getName() + "</Name>\r\n"); |
| | | recordXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n"); |
| | | recordXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n"); |
| | | recordXml.append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n"); |
| | | recordXml.append("<Type>" + recordItem.getType() + "</Type>\r\n"); |
| | | if (!StringUtils.isEmpty(recordItem.getFileSize())) { |
| | | recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n"); |
| | | } |
| | | if (!StringUtils.isEmpty(recordItem.getFilePath())) { |
| | | recordXml.append("<FilePath>" + recordItem.getFilePath() + "</FilePath>\r\n"); |
| | | } |
| | | } |
| | | recordXml.append("</Item>\r\n"); |
| | | } |
| | | } |
| | | recordXml.append("</Item>\r\n"); |
| | | } |
| | | |
| | | recordXml.append("</RecordList>\r\n"); |
| | |
| | | import javax.sip.header.FromHeader; |
| | | import javax.sip.header.HeaderAddress; |
| | | import javax.sip.header.ToHeader; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.Timer; |
| | | import java.util.TimerTask; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * SIP命令类型: ACK请求 |
| | |
| | | String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); |
| | | SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId, null, callIdHeader.getCallId()); |
| | | String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; |
| | | String deviceId = sendRtpItem.getDeviceId(); |
| | | StreamInfo streamInfo = null; |
| | | if (sendRtpItem.isPlay()) { |
| | | streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); |
| | | }else { |
| | | streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId); |
| | | } |
| | | if (streamInfo == null) { |
| | | streamInfo = new StreamInfo(); |
| | | streamInfo.setApp(sendRtpItem.getApp()); |
| | | streamInfo.setStream(sendRtpItem.getStreamId()); |
| | | } |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | logger.info("收到ACK,开始向上级推流 rtp/{}", sendRtpItem.getStreamId()); |
| | | Map<String, Object> param = new HashMap<>(); |
| | | param.put("vhost","__defaultVhost__"); |
| | | param.put("app",streamInfo.getApp()); |
| | | param.put("stream",streamInfo.getStream()); |
| | | param.put("app",sendRtpItem.getApp()); |
| | | param.put("stream",sendRtpItem.getStreamId()); |
| | | param.put("ssrc", sendRtpItem.getSsrc()); |
| | | param.put("dst_url",sendRtpItem.getIp()); |
| | | param.put("dst_port", sendRtpItem.getPort()); |
| | | param.put("is_udp", is_Udp); |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| | | if (jsonObject.getInteger("code") != 0) { |
| | | logger.info("监听流以等待流上线{}/{}", streamInfo.getApp(), streamInfo.getStream()); |
| | | // 监听流上线 |
| | | // 添加订阅 |
| | | JSONObject subscribeKey = new JSONObject(); |
| | | subscribeKey.put("app", "rtp"); |
| | | subscribeKey.put("stream", streamInfo.getStream()); |
| | | subscribeKey.put("regist", true); |
| | | subscribeKey.put("schema", "rtmp"); |
| | | subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId()); |
| | | subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, |
| | | (MediaServerItem mediaServerItemInUse, JSONObject json)->{ |
| | | zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| | | }); |
| | | } |
| | | param.put("src_port", sendRtpItem.getLocalPort()); |
| | | zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| | | |
| | | |
| | | |
| | | // if (streamInfo == null) { // 流还没上来,对方就回复ack |
| | | // logger.info("监听流以等待流上线1 rtp/{}", sendRtpItem.getStreamId()); |
| | | // // 监听流上线 |
| | | // // 添加订阅 |
| | | // JSONObject subscribeKey = new JSONObject(); |
| | | // subscribeKey.put("app", "rtp"); |
| | | // subscribeKey.put("stream", sendRtpItem.getStreamId()); |
| | | // subscribeKey.put("regist", true); |
| | | // subscribeKey.put("schema", "rtmp"); |
| | | // subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId()); |
| | | // subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, |
| | | // (MediaServerItem mediaServerItemInUse, JSONObject json)->{ |
| | | // Map<String, Object> param = new HashMap<>(); |
| | | // param.put("vhost","__defaultVhost__"); |
| | | // param.put("app",json.getString("app")); |
| | | // param.put("stream",json.getString("stream")); |
| | | // param.put("ssrc", sendRtpItem.getSsrc()); |
| | | // param.put("dst_url",sendRtpItem.getIp()); |
| | | // param.put("dst_port", sendRtpItem.getPort()); |
| | | // param.put("is_udp", is_Udp); |
| | | // param.put("src_port", sendRtpItem.getLocalPort()); |
| | | // zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| | | // }); |
| | | // }else { |
| | | // Map<String, Object> param = new HashMap<>(); |
| | | // param.put("vhost","__defaultVhost__"); |
| | | // param.put("app",streamInfo.getApp()); |
| | | // param.put("stream",streamInfo.getStream()); |
| | | // param.put("ssrc", sendRtpItem.getSsrc()); |
| | | // param.put("dst_url",sendRtpItem.getIp()); |
| | | // param.put("dst_port", sendRtpItem.getPort()); |
| | | // param.put("is_udp", is_Udp); |
| | | // param.put("src_port", sendRtpItem.getLocalPort()); |
| | | // |
| | | // JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| | | // if (jsonObject.getInteger("code") != 0) { |
| | | // logger.info("监听流以等待流上线2 {}/{}", streamInfo.getApp(), streamInfo.getStream()); |
| | | // // 监听流上线 |
| | | // // 添加订阅 |
| | | // JSONObject subscribeKey = new JSONObject(); |
| | | // subscribeKey.put("app", "rtp"); |
| | | // subscribeKey.put("stream", streamInfo.getStream()); |
| | | // subscribeKey.put("regist", true); |
| | | // subscribeKey.put("schema", "rtmp"); |
| | | // subscribeKey.put("mediaServerId", sendRtpItem.getMediaServerId()); |
| | | // subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, |
| | | // (MediaServerItem mediaServerItemInUse, JSONObject json)->{ |
| | | // zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| | | // }); |
| | | // } |
| | | // } |
| | | } |
| | | } |
| | | } |
| | |
| | | param.put("app",sendRtpItem.getApp()); |
| | | param.put("stream",streamId); |
| | | param.put("ssrc",sendRtpItem.getSsrc()); |
| | | logger.info("停止向上级推流:" + streamId); |
| | | logger.info("收到bye:停止向上级推流:" + streamId); |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); |
| | | redisCatchStorage.deleteSendRTPServer(platformGbId, channelId, callIdHeader.getCallId(), null); |
| | | int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId); |
| | | if (totalReaderCount <= 0) { |
| | | logger.info(streamId + "无其它观看者,通知设备停止推流"); |
| | | cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId); |
| | | logger.info("收到bye: {}无其它观看者,通知设备停止推流", streamId); |
| | | if (sendRtpItem.isPlay()) { |
| | | cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId, null); |
| | | } |
| | | } |
| | | } |
| | | // 可能是设备主动停止 |
| | |
| | | import com.genersoft.iot.vmp.conf.DynamicTask; |
| | | import com.genersoft.iot.vmp.gb28181.bean.*; |
| | | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| | | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| | |
| | | |
| | | @Autowired |
| | | private SIPProcessorObserver sipProcessorObserver; |
| | | |
| | | @Autowired |
| | | private VideoStreamSessionManager sessionManager; |
| | | |
| | | |
| | | @Override |
| | |
| | | } |
| | | String username = sdp.getOrigin().getUsername(); |
| | | String addressStr = sdp.getOrigin().getAddress(); |
| | | |
| | | logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc); |
| | | Device device = null; |
| | | // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标 |
| | |
| | | sendRtpItem.setDialog(dialogByteArray); |
| | | byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction()); |
| | | sendRtpItem.setTransaction(transactionByteArray); |
| | | // 写入redis, 超时时回复 |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | |
| | | |
| | | Long finalStartTime = startTime; |
| | | Long finalStopTime = stopTime; |
| | | ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON)->{ |
| | | logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", sendRtpItem.getApp(), sendRtpItem.getStreamId()); |
| | | String app = responseJSON.getString("app"); |
| | | String stream = responseJSON.getString("stream"); |
| | | logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", app, stream); |
| | | // * 0 等待设备推流上来 |
| | | // * 1 下级已经推流,等待上级平台回复ack |
| | | // * 2 推流中 |
| | |
| | | e.printStackTrace(); |
| | | } |
| | | }); |
| | | sendRtpItem.setApp("rtp"); |
| | | if ("Playback".equals(sessionName)) { |
| | | sendRtpItem.setPlay(false); |
| | | sendRtpItem.setStreamId(ssrc); |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true); |
| | | sendRtpItem.setStreamId(ssrcInfo.getStream()); |
| | | // 写入redis, 超时时回复 |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | playService.playBack(device.getDeviceId(), channelId, format.format(start), format.format(end),result -> { |
| | | if (result.getCode() != 0){ |
| | | logger.warn("录像回放失败"); |
| | | if (result.getEvent() != null) { |
| | | errorEvent.response(result.getEvent()); |
| | | playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, format.format(start), |
| | | format.format(end), null, result -> { |
| | | if (result.getCode() != 0){ |
| | | logger.warn("录像回放失败"); |
| | | if (result.getEvent() != null) { |
| | | errorEvent.response(result.getEvent()); |
| | | } |
| | | redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); |
| | | try { |
| | | responseAck(evt, Response.REQUEST_TIMEOUT); |
| | | } catch (SipException e) { |
| | | e.printStackTrace(); |
| | | } catch (InvalidArgumentException e) { |
| | | e.printStackTrace(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | }else { |
| | | if (result.getMediaServerItem() != null) { |
| | | hookEvent.response(result.getMediaServerItem(), result.getResponse()); |
| | | } |
| | | } |
| | | redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); |
| | | try { |
| | | responseAck(evt, Response.REQUEST_TIMEOUT); |
| | | } catch (SipException e) { |
| | | e.printStackTrace(); |
| | | } catch (InvalidArgumentException e) { |
| | | e.printStackTrace(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | }else { |
| | | if (result.getMediaServerItem() != null) { |
| | | hookEvent.response(result.getMediaServerItem(), result.getResponse()); |
| | | } |
| | | } |
| | | }); |
| | | }); |
| | | }else { |
| | | sendRtpItem.setPlay(true); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId); |
| | | if (streamInfo == null) { |
| | | SsrcTransaction playTransaction = sessionManager.getSsrcTransaction(device.getDeviceId(), channelId, "play", null); |
| | | if (playTransaction != null) { |
| | | Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, "rtp", playTransaction.getStream()); |
| | | if (!streamReady) { |
| | | playTransaction = null; |
| | | } |
| | | } |
| | | if (playTransaction == null) { |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true); |
| | | if (mediaServerItem.isRtpEnable()) { |
| | | sendRtpItem.setStreamId(String.format("%s_%s", device.getDeviceId(), channelId)); |
| | | }else { |
| | | sendRtpItem.setStreamId(ssrcInfo.getStream()); |
| | | } |
| | | sendRtpItem.setPlay(false); |
| | | playService.play(mediaServerItem,device.getDeviceId(), channelId, hookEvent, errorEvent, ()->{ |
| | | // 写入redis, 超时时回复 |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | playService.play(mediaServerItem, ssrcInfo, device, channelId, hookEvent, errorEvent, (code, msg)->{ |
| | | redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); |
| | | }); |
| | | }, null); |
| | | }else { |
| | | sendRtpItem.setStreamId(streamInfo.getStream()); |
| | | hookEvent.response(mediaServerItem, null); |
| | | sendRtpItem.setStreamId(playTransaction.getStream()); |
| | | // 写入redis, 超时时回复 |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("app", sendRtpItem.getApp()); |
| | | jsonObject.put("stream", sendRtpItem.getStreamId()); |
| | | hookEvent.response(mediaServerItem, jsonObject); |
| | | } |
| | | } |
| | | }else if (gbStream != null) { |
| | |
| | | import javax.sip.InvalidArgumentException; |
| | | import javax.sip.RequestEvent; |
| | | import javax.sip.SipException; |
| | | import javax.sip.header.CallIdHeader; |
| | | import javax.sip.message.Response; |
| | | import java.text.ParseException; |
| | | |
| | |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); |
| | | String NotifyType =getText(rootElement, "NotifyType"); |
| | | if (NotifyType.equals("121")){ |
| | | logger.info("媒体播放完毕,通知关流"); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(device.getDeviceId(), "*"); |
| | | if (streamInfo != null) { |
| | | redisCatchStorage.stopPlayback(streamInfo); |
| | | cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream()); |
| | | } |
| | | String channelId =getText(rootElement, "DeviceID"); |
| | | redisCatchStorage.stopPlayback(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); |
| | | cmder.streamByeCmd(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); |
| | | // TODO 如果级联播放,需要给上级发送此通知 |
| | | |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; |
| | | import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; |
| | |
| | | |
| | | @Autowired |
| | | private SIPProcessorObserver sipProcessorObserver; |
| | | |
| | | @Autowired |
| | | private SubscribeHolder subscribeHolder; |
| | | |
| | | @Override |
| | | public void afterPropertiesSet() throws Exception { |
| | |
| | | // 注册/注销成功 |
| | | logger.info(String.format("%s %s成功", platformGBId, action)); |
| | | redisCatchStorage.delPlatformRegisterInfo(callId); |
| | | parentPlatform.setStatus("注册".equals(action)); |
| | | redisCatchStorage.delPlatformCatchInfo(platformGBId); |
| | | // 取回Expires设置,避免注销过程中被置为0 |
| | | if (!parentPlatformCatch.getParentPlatform().getExpires().equals("0")) { |
| | | ParentPlatform parentPlatformTmp = storager.queryParentPlatByServerGBId(platformGBId); |
| | | String expires = parentPlatformTmp.getExpires(); |
| | | parentPlatform.setExpires(expires); |
| | | parentPlatform.setId(parentPlatformTmp.getId()); |
| | | redisCatchStorage.updatePlatformRegister(parentPlatform); |
| | | redisCatchStorage.updatePlatformKeepalive(parentPlatform); |
| | | parentPlatformCatch.setParentPlatform(parentPlatform); |
| | | redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); |
| | | } |
| | | ParentPlatform parentPlatformTmp = storager.queryParentPlatByServerGBId(platformGBId); |
| | | parentPlatformTmp.setStatus("注册".equals(action)); |
| | | redisCatchStorage.updatePlatformRegister(parentPlatformTmp); |
| | | redisCatchStorage.updatePlatformKeepalive(parentPlatformTmp); |
| | | parentPlatformCatch.setParentPlatform(parentPlatformTmp); |
| | | redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); |
| | | storager.updateParentPlatformStatus(platformGBId, "注册".equals(action)); |
| | | if ("注销".equals(action)) { |
| | | subscribeHolder.removeCatalogSubscribe(platformGBId); |
| | | subscribeHolder.removeMobilePositionSubscribe(platformGBId); |
| | | } |
| | | |
| | | } |
| | | } |
| | |
| | | |
| | | Map<String, Object> param = new HashMap<>(); |
| | | int result = -1; |
| | | /** |
| | | * 不设置推流端口端则使用随机端口 |
| | | */ |
| | | if (StringUtils.isEmpty(mediaServerItem.getSendRtpPortRange())){ |
| | | param.put("port", 0); |
| | | }else { |
| | | // 不设置推流端口端则使用随机端口 |
| | | if (!StringUtils.isEmpty(mediaServerItem.getSendRtpPortRange())){ |
| | | int newPort = getPortFromportRange(mediaServerItem); |
| | | param.put("port", newPort); |
| | | } |
| | |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| | | import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback; |
| | | import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; |
| | | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback; |
| | | import com.genersoft.iot.vmp.service.bean.PlayBackCallback; |
| | | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| | | import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.web.context.request.async.DeferredResult; |
| | |
| | | |
| | | void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid); |
| | | |
| | | void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, |
| | | ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, |
| | | InviteTimeOutCallback timeoutCallback, String uuid); |
| | | PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent, Runnable timeoutCallback); |
| | | |
| | | MediaServerItem getNewMediaServerItem(Device device); |
| | | |
| | | void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String toString); |
| | | void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String toString); |
| | | |
| | | DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback errorCallBack); |
| | | DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); |
| | | DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); |
| | | |
| | | void zlmServerOffline(String mediaServerId); |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.service.bean; |
| | | |
| | | public interface InviteTimeOutCallback { |
| | | |
| | | void run(int code, String msg); // code: 0 sip超时, 1 收流超时 |
| | | } |
| | |
| | | import javax.sip.RequestEvent; |
| | | |
| | | public class PlayBackResult<T> { |
| | | private int code; |
| | | private T data; |
| | | private MediaServerItem mediaServerItem; |
| | | private int code; |
| | | private T data; |
| | | private MediaServerItem mediaServerItem; |
| | | private JSONObject response; |
| | | private SipSubscribe.EventResult event; |
| | | |
| | |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.service.IMediaServerService; |
| | | import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback; |
| | | import com.genersoft.iot.vmp.service.bean.PlayBackCallback; |
| | | import com.genersoft.iot.vmp.service.bean.PlayBackResult; |
| | | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| | |
| | | import com.genersoft.iot.vmp.service.IMediaService; |
| | | import com.genersoft.iot.vmp.service.IPlayService; |
| | | import gov.nist.javax.sip.stack.SIPDialog; |
| | | import jdk.nashorn.internal.ir.RuntimeNode; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | import org.springframework.util.ResourceUtils; |
| | | import org.springframework.web.context.request.async.DeferredResult; |
| | | |
| | | import javax.sip.header.CallIdHeader; |
| | | import javax.sip.header.Header; |
| | | import javax.sip.message.Request; |
| | | import java.io.FileNotFoundException; |
| | | import java.util.*; |
| | | |
| | |
| | | |
| | | @Autowired |
| | | private UserSetup userSetup; |
| | | |
| | | |
| | | |
| | | |
| | | @Override |
| | |
| | | e.printStackTrace(); |
| | | } |
| | | }); |
| | | if (streamInfo == null) { |
| | | String streamId = null; |
| | | if (mediaServerItem.isRtpEnable()) { |
| | | streamId = String.format("%s_%s", device.getDeviceId(), channelId); |
| | | } |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId); |
| | | // 超时处理 |
| | | Timer timer = new Timer(); |
| | | timer.schedule(new TimerTask() { |
| | | @Override |
| | | public void run() { |
| | | logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| | | if (timeoutCallback != null) { |
| | | timeoutCallback.run(); |
| | | } |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(-1); |
| | | SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream()); |
| | | if (dialog != null) { |
| | | wvpResult.setMsg("收流超时,请稍候重试"); |
| | | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| | | cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| | | }else { |
| | | wvpResult.setMsg("点播超时,请稍候重试"); |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| | | mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream()); |
| | | streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); |
| | | } |
| | | |
| | | msg.setData(wvpResult); |
| | | |
| | | // 回复之前所有的点播请求 |
| | | resultHolder.invokeAllResult(msg); |
| | | } |
| | | }, userSetup.getPlayTimeout()); |
| | | // 发送点播消息 |
| | | cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInUse, JSONObject response) -> { |
| | | logger.info("收到订阅消息: " + response.toJSONString()); |
| | | timer.cancel(); |
| | | onPublishHandlerForPlay(mediaServerItemInUse, response, deviceId, channelId, uuid); |
| | | if (hookEvent != null) { |
| | | hookEvent.response(mediaServerItem, response); |
| | | } |
| | | }, (event) -> { |
| | | timer.cancel(); |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(-1); |
| | | // 点播返回sip错误 |
| | | mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream()); |
| | | // 释放ssrc |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| | | streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); |
| | | |
| | | wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); |
| | | msg.setData(wvpResult); |
| | | resultHolder.invokeAllResult(msg); |
| | | if (errorEvent != null) { |
| | | errorEvent.response(event); |
| | | } |
| | | }); |
| | | } else { |
| | | if (streamInfo != null) { |
| | | String streamId = streamInfo.getStream(); |
| | | if (streamId == null) { |
| | | WVPResult wvpResult = new WVPResult(); |
| | |
| | | if (hookEvent != null) { |
| | | hookEvent.response(mediaServerItem, JSONObject.parseObject(JSON.toJSONString(streamInfo))); |
| | | } |
| | | } else { |
| | | // TODO 点播前是否重置状态 |
| | | }else { |
| | | redisCatchStorage.stopPlay(streamInfo); |
| | | storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| | | String streamId2 = null; |
| | | if (mediaServerItem.isRtpEnable()) { |
| | | streamId2 = String.format("%s_%s", device.getDeviceId(), channelId); |
| | | } |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId2); |
| | | // 超时处理 |
| | | Timer timer = new Timer(); |
| | | timer.schedule(new TimerTask() { |
| | | @Override |
| | | public void run() { |
| | | logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| | | if (timeoutCallback != null) { |
| | | timeoutCallback.run(); |
| | | } |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(-1); |
| | | SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream()); |
| | | if (dialog != null) { |
| | | wvpResult.setMsg("收流超时,请稍候重试"); |
| | | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| | | cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| | | }else { |
| | | wvpResult.setMsg("点播超时,请稍候重试"); |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| | | mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream()); |
| | | streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); |
| | | } |
| | | |
| | | msg.setData(wvpResult); |
| | | // 回复之前所有的点播请求 |
| | | resultHolder.invokeAllResult(msg); |
| | | } |
| | | }, userSetup.getPlayTimeout()); |
| | | cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { |
| | | logger.info("收到订阅消息: " + response.toJSONString()); |
| | | onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid); |
| | | }, (event) -> { |
| | | mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream()); |
| | | // 释放ssrc |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| | | streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(-1); |
| | | wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); |
| | | msg.setData(wvpResult); |
| | | resultHolder.invokeAllResult(msg); |
| | | }); |
| | | streamInfo = null; |
| | | } |
| | | |
| | | } |
| | | if (streamInfo == null) { |
| | | String streamId = null; |
| | | if (mediaServerItem.isRtpEnable()) { |
| | | streamId = String.format("%s_%s", device.getDeviceId(), channelId); |
| | | } |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId); |
| | | play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response)->{ |
| | | if (hookEvent != null) { |
| | | hookEvent.response(mediaServerItem, response); |
| | | } |
| | | }, event -> { |
| | | // sip error错误 |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(-1); |
| | | wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); |
| | | msg.setData(wvpResult); |
| | | resultHolder.invokeAllResult(msg); |
| | | if (errorEvent != null) { |
| | | errorEvent.response(event); |
| | | } |
| | | }, (code, msgStr)->{ |
| | | // invite点播超时 |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(-1); |
| | | if (code == 0) { |
| | | wvpResult.setMsg("点播超时,请稍候重试"); |
| | | }else if (code == 1) { |
| | | wvpResult.setMsg("收流超时,请稍候重试"); |
| | | } |
| | | 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) { |
| | | |
| | | String streamId = null; |
| | | if (mediaServerItem.isRtpEnable()) { |
| | | streamId = String.format("%s_%s", device.getDeviceId(), channelId); |
| | | } |
| | | if (ssrcInfo == null) { |
| | | ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId); |
| | | } |
| | | |
| | | return playResult; |
| | | // 超时处理 |
| | | Timer timer = new Timer(); |
| | | SSRCInfo finalSsrcInfo = ssrcInfo; |
| | | timer.schedule(new TimerTask() { |
| | | @Override |
| | | public void run() { |
| | | logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", device.getDeviceId(), channelId)); |
| | | |
| | | SIPDialog dialog = streamSession.getDialogByStream(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); |
| | | if (dialog != null) { |
| | | timeoutCallback.run(1, "收流超时"); |
| | | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| | | cmder.streamByeCmd(device.getDeviceId(), channelId, finalSsrcInfo.getStream(), null); |
| | | }else { |
| | | timeoutCallback.run(0, "点播超时"); |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); |
| | | mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); |
| | | streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); |
| | | } |
| | | } |
| | | }, userSetup.getPlayTimeout()); |
| | | |
| | | cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { |
| | | logger.info("收到订阅消息: " + response.toJSONString()); |
| | | timer.cancel(); |
| | | // hook响应 |
| | | onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid); |
| | | hookEvent.response(mediaServerItemInuse, response); |
| | | }, (event) -> { |
| | | timer.cancel(); |
| | | mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); |
| | | // 释放ssrc |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); |
| | | streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); |
| | | errorEvent.response(event); |
| | | }); |
| | | } |
| | | |
| | | @Override |
| | | public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) { |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setId(uuid); |
| | | if (uuid != null) { |
| | | msg.setId(uuid); |
| | | } |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId); |
| | | StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); |
| | | if (streamInfo != null) { |
| | |
| | | storager.startPlay(deviceId, channelId, streamInfo.getStream()); |
| | | } |
| | | redisCatchStorage.startPlay(streamInfo); |
| | | msg.setData(JSON.toJSONString(streamInfo)); |
| | | |
| | | WVPResult wvpResult = new WVPResult(); |
| | | wvpResult.setCode(0); |
| | |
| | | return mediaServerItem; |
| | | } |
| | | |
| | | @Override |
| | | public DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, |
| | | String endTime,InviteStreamCallback inviteStreamCallback, |
| | | PlayBackCallback callback) { |
| | | Device device = storager.queryVideoDevice(deviceId); |
| | | if (device == null) return null; |
| | | MediaServerItem newMediaServerItem = getNewMediaServerItem(device); |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); |
| | | |
| | | return playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback); |
| | | } |
| | | |
| | | @Override |
| | | public DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, PlayBackCallback callback) { |
| | | public DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, |
| | | String deviceId, String channelId, String startTime, |
| | | String endTime, InviteStreamCallback infoCallBack, |
| | | PlayBackCallback playBackCallback) { |
| | | if (mediaServerItem == null || ssrcInfo == null) return null; |
| | | String uuid = UUID.randomUUID().toString(); |
| | | String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; |
| | | DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L); |
| | |
| | | return result; |
| | | } |
| | | |
| | | MediaServerItem newMediaServerItem = getNewMediaServerItem(device); |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); |
| | | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId, uuid, result); |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setId(uuid); |
| | |
| | | logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| | | playBackResult.setCode(-1); |
| | | playBackResult.setData(msg); |
| | | callback.call(playBackResult); |
| | | playBackCallback.call(playBackResult); |
| | | SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream()); |
| | | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| | | if (dialog != null) { |
| | | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| | | cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| | | cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); |
| | | }else { |
| | | mediaServerService.releaseSsrc(newMediaServerItem.getId(), ssrcInfo.getSsrc()); |
| | | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| | | mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream()); |
| | | streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); |
| | | } |
| | | cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| | | cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); |
| | | // 回复之前所有的点播请求 |
| | | callback.call(playBackResult); |
| | | playBackCallback.call(playBackResult); |
| | | } |
| | | }, userSetup.getPlayTimeout()); |
| | | cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> { |
| | | logger.info("收到订阅消息: " + response.toJSONString()); |
| | | timer.cancel(); |
| | | StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); |
| | | if (streamInfo == null) { |
| | | logger.warn("设备回放API调用失败!"); |
| | | msg.setData("设备回放API调用失败!"); |
| | | playBackResult.setCode(-1); |
| | | playBackResult.setData(msg); |
| | | callback.call(playBackResult); |
| | | return; |
| | | } |
| | | redisCatchStorage.startPlayback(streamInfo); |
| | | msg.setData(JSON.toJSONString(streamInfo)); |
| | | playBackResult.setCode(0); |
| | | playBackResult.setData(msg); |
| | | playBackResult.setMediaServerItem(mediaServerItem); |
| | | playBackResult.setResponse(response); |
| | | callback.call(playBackResult); |
| | | }, event -> { |
| | | timer.cancel(); |
| | | msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg)); |
| | | playBackResult.setCode(-1); |
| | | playBackResult.setData(msg); |
| | | playBackResult.setEvent(event); |
| | | callback.call(playBackResult); |
| | | streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| | | }); |
| | | cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack, |
| | | (InviteStreamInfo inviteStreamInfo) -> { |
| | | logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString()); |
| | | timer.cancel(); |
| | | StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); |
| | | if (streamInfo == null) { |
| | | logger.warn("设备回放API调用失败!"); |
| | | msg.setData("设备回放API调用失败!"); |
| | | playBackResult.setCode(-1); |
| | | playBackResult.setData(msg); |
| | | playBackCallback.call(playBackResult); |
| | | return; |
| | | } |
| | | redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId()); |
| | | msg.setData(JSON.toJSONString(streamInfo)); |
| | | playBackResult.setCode(0); |
| | | playBackResult.setData(msg); |
| | | playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem()); |
| | | playBackResult.setResponse(inviteStreamInfo.getResponse()); |
| | | playBackCallback.call(playBackResult); |
| | | }, event -> { |
| | | timer.cancel(); |
| | | msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg)); |
| | | playBackResult.setCode(-1); |
| | | playBackResult.setData(msg); |
| | | playBackResult.setEvent(event); |
| | | playBackCallback.call(playBackResult); |
| | | streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| | | }); |
| | | return result; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void onPublishHandlerForDownload(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) { |
| | | public void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String uuid) { |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId); |
| | | msg.setId(uuid); |
| | | StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); |
| | | StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); |
| | | if (streamInfo != null) { |
| | | redisCatchStorage.startDownload(streamInfo); |
| | | redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId()); |
| | | msg.setData(JSON.toJSONString(streamInfo)); |
| | | resultHolder.invokeResult(msg); |
| | | } else { |
| | |
| | | if (allSsrc.size() > 0) { |
| | | for (SsrcTransaction ssrcTransaction : allSsrc) { |
| | | if(ssrcTransaction.getMediaServerId().equals(mediaServerId)) { |
| | | cmder.streamByeCmd(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); |
| | | cmder.streamByeCmd(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), |
| | | ssrcTransaction.getStream(), null); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | StreamInfo queryPlayByStreamId(String steamId); |
| | | |
| | | StreamInfo queryPlaybackByStreamId(String steamId); |
| | | |
| | | StreamInfo queryPlayByDevice(String deviceId, String channelId); |
| | | |
| | | Map<String, StreamInfo> queryPlayByDeviceId(String deviceId); |
| | | |
| | | boolean startPlayback(StreamInfo stream); |
| | | boolean startPlayback(StreamInfo stream, String callId); |
| | | |
| | | boolean stopPlayback(StreamInfo streamInfo); |
| | | boolean stopPlayback(String deviceId, String channelId, String stream, String callId); |
| | | |
| | | StreamInfo queryPlaybackByDevice(String deviceId, String code); |
| | | StreamInfo queryPlayback(String deviceId, String channelID, String stream, String callId); |
| | | |
| | | void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch); |
| | | |
| | |
| | | * 开始下载录像时存入 |
| | | * @param streamInfo |
| | | */ |
| | | boolean startDownload(StreamInfo streamInfo); |
| | | boolean startDownload(StreamInfo streamInfo, String callId); |
| | | |
| | | StreamInfo queryDownloadByStreamId(String streamId); |
| | | StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId); |
| | | |
| | | /** |
| | | * 查找第三方系统留下的国标预设值 |
| | |
| | | int cleanChannelForGB(String platformId); |
| | | |
| | | @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId='${channelId}' and pgc.platformId='${platformId}'") |
| | | DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); |
| | | List<DeviceChannel> queryChannelInParentPlatform(String platformId, String channelId); |
| | | |
| | | @Select(" select dc.channelId as id, dc.name as name, pgc.platformId as platformId, pgc.catalogId as parentId, 0 as childrenCount, 1 as type " + |
| | | " from device_channel dc left join platform_gb_channel pgc on dc.id = pgc.deviceChannelId " + |
| | |
| | | " left join device_channel dc on dc.id = pgc.deviceChannelId\n" + |
| | | " left join device d on dc.deviceId = d.deviceId\n" + |
| | | "where dc.channelId = #{channelId} and pgc.platformId=#{platformId}") |
| | | Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); |
| | | List<Device> queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); |
| | | |
| | | @Delete("<script> "+ |
| | | "DELETE FROM platform_gb_channel WHERE catalogId=#{id}" + |
| | |
| | | "left join platform_gb_stream pgs on " + |
| | | "pp.serverGBId = pgs.platformId " + |
| | | "left join gb_stream gs " + |
| | | "gs.gbStreamId = pgs.gbStreamId " + |
| | | "on gs.gbStreamId = pgs.gbStreamId " + |
| | | "WHERE " + |
| | | "gs.app = #{app} " + |
| | | "AND gs.stream = #{stream}" + |
| | |
| | | } |
| | | |
| | | @Override |
| | | public StreamInfo queryPlaybackByStreamId(String streamId) { |
| | | List<Object> playLeys = redis.scan(String.format("%S_%s_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, userSetup.getServerId(), streamId)); |
| | | if (playLeys == null || playLeys.size() == 0) return null; |
| | | return (StreamInfo)redis.get(playLeys.get(0).toString()); |
| | | } |
| | | |
| | | @Override |
| | | public StreamInfo queryPlayByDevice(String deviceId, String channelId) { |
| | | List<Object> playLeys = redis.scan(String.format("%S_%s_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX, |
| | | userSetup.getServerId(), |
| | |
| | | |
| | | |
| | | @Override |
| | | public boolean startPlayback(StreamInfo stream) { |
| | | return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | userSetup.getServerId(), stream.getStream(), stream.getDeviceID(), stream.getChannelId()), stream); |
| | | public boolean startPlayback(StreamInfo stream, String callId) { |
| | | return redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream); |
| | | } |
| | | |
| | | @Override |
| | | public boolean startDownload(StreamInfo streamInfo) { |
| | | return redis.set(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, userSetup.getServerId(), |
| | | streamInfo.getStream(), streamInfo.getDeviceID(), streamInfo.getChannelId()), streamInfo); |
| | | public boolean startDownload(StreamInfo stream, String callId) { |
| | | return redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, |
| | | userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream); |
| | | } |
| | | |
| | | @Override |
| | | public boolean stopPlayback(StreamInfo streamInfo) { |
| | | if (streamInfo == null) return false; |
| | | DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| | | public boolean stopPlayback(String deviceId, String channelId, String stream, String callId) { |
| | | DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId); |
| | | if (deviceChannel != null) { |
| | | deviceChannel.setStreamId(null); |
| | | deviceChannel.setDeviceId(streamInfo.getDeviceID()); |
| | | deviceChannel.setDeviceId(deviceId); |
| | | deviceChannelMapper.update(deviceChannel); |
| | | } |
| | | return redis.del(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | if (deviceId == null) deviceId = "*"; |
| | | if (channelId == null) channelId = "*"; |
| | | if (stream == null) stream = "*"; |
| | | if (callId == null) callId = "*"; |
| | | String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | userSetup.getServerId(), |
| | | streamInfo.getStream(), |
| | | streamInfo.getDeviceID(), |
| | | streamInfo.getChannelId())); |
| | | deviceId, |
| | | channelId, |
| | | stream, |
| | | callId |
| | | ); |
| | | List<Object> scan = redis.scan(key); |
| | | if (scan.size() > 0) { |
| | | for (Object keyObj : scan) { |
| | | redis.del((String) keyObj); |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public StreamInfo queryPlaybackByDevice(String deviceId, String code) { |
| | | // String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | // deviceId, |
| | | // code); |
| | | List<Object> playLeys = redis.scan(String.format("%S_%s_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | public StreamInfo queryPlayback(String deviceId, String channelId, String stream, String callId) { |
| | | if (stream == null && callId == null) { |
| | | return null; |
| | | } |
| | | if (deviceId == null) deviceId = "*"; |
| | | if (channelId == null) channelId = "*"; |
| | | if (stream == null) stream = "*"; |
| | | if (callId == null) callId = "*"; |
| | | String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | userSetup.getServerId(), |
| | | deviceId, |
| | | code)); |
| | | if (playLeys == null || playLeys.size() == 0) { |
| | | playLeys = redis.scan(String.format("%S_%s_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | userSetup.getServerId(), |
| | | deviceId)); |
| | | channelId, |
| | | stream, |
| | | callId |
| | | ); |
| | | List<Object> streamInfoScan = redis.scan(key); |
| | | if (streamInfoScan.size() > 0) { |
| | | return (StreamInfo) redis.get((String) streamInfoScan.get(0)); |
| | | }else { |
| | | return null; |
| | | } |
| | | if (playLeys == null || playLeys.size() == 0) return null; |
| | | return (StreamInfo)redis.get(playLeys.get(0).toString()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | } |
| | | |
| | | List<Object> playBackers = redis.scan(String.format("%S_%s_*_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | List<Object> playBackers = redis.scan(String.format("%S_%s_%s_*_*_*", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| | | userSetup.getServerId(), |
| | | deviceId)); |
| | | if (playBackers.size() > 0) { |
| | |
| | | } |
| | | |
| | | @Override |
| | | public StreamInfo queryDownloadByStreamId(String streamId) { |
| | | List<Object> playLeys = redis.scan(String.format("%S_%s_%s_*", VideoManagerConstants.DOWNLOAD_PREFIX, userSetup.getServerId(), streamId)); |
| | | if (playLeys == null || playLeys.size() == 0) return null; |
| | | return (StreamInfo)redis.get(playLeys.get(0).toString()); |
| | | public StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId) { |
| | | if (stream == null && callId == null) { |
| | | return null; |
| | | } |
| | | if (deviceId == null) deviceId = "*"; |
| | | if (channelId == null) channelId = "*"; |
| | | if (stream == null) stream = "*"; |
| | | if (callId == null) callId = "*"; |
| | | String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX, |
| | | userSetup.getServerId(), |
| | | deviceId, |
| | | channelId, |
| | | stream, |
| | | callId |
| | | ); |
| | | List<Object> streamInfoScan = redis.scan(key); |
| | | if (streamInfoScan.size() > 0) { |
| | | return (StreamInfo) redis.get((String) streamInfoScan.get(0)); |
| | | }else { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | @Override |
| | | public DeviceChannel queryChannelInParentPlatform(String platformId, String channelId) { |
| | | DeviceChannel channel = platformChannelMapper.queryChannelInParentPlatform(platformId, channelId); |
| | | return channel; |
| | | List<DeviceChannel> channels = platformChannelMapper.queryChannelInParentPlatform(platformId, channelId); |
| | | if (channels.size() > 1) { |
| | | // 出现长度大于0的时候肯定是国标通道的ID重复了 |
| | | logger.warn("国标ID存在重复:{}", channelId); |
| | | } |
| | | if (channels.size() == 0) { |
| | | return null; |
| | | }else { |
| | | return channels.get(0); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | @Override |
| | | public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) { |
| | | Device device = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); |
| | | return device; |
| | | List<Device> devices = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); |
| | | if (devices.size() > 1) { |
| | | // 出现长度大于0的时候肯定是国标通道的ID重复了 |
| | | logger.warn("国标ID存在重复:{}", channelId); |
| | | } |
| | | if (devices.size() == 0) { |
| | | return null; |
| | | }else { |
| | | return devices.get(0); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | @Override |
| | | public List<ParentPlatform> queryPlatFormListForStreamWithGBId(String app, String stream, List<String> platforms) { |
| | | if (platforms == null || platforms.size() == 0) { |
| | | return new ArrayList<>(); |
| | | } |
| | | return platformGbStreamMapper.queryPlatFormListForGBWithGBId(app, stream, platforms); |
| | | } |
| | | |
| | |
| | | import com.genersoft.iot.vmp.conf.UserSetup; |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| | | import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; |
| | | import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| | |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Autowired |
| | | private SubscribeHolder subscribeHolder; |
| | | |
| | | @Autowired |
| | | private ISIPCommanderForPlatform commanderForPlatform; |
| | |
| | | }) |
| | | public PageInfo<ParentPlatform> platforms(@PathVariable int page, @PathVariable int count) { |
| | | |
| | | // if (logger.isDebugEnabled()) { |
| | | // logger.debug("查询所有上级设备API调用"); |
| | | // } |
| | | return storager.queryParentPlatformList(page, count); |
| | | PageInfo<ParentPlatform> parentPlatformPageInfo = storager.queryParentPlatformList(page, count); |
| | | if (parentPlatformPageInfo.getList().size() > 0) { |
| | | for (ParentPlatform platform : parentPlatformPageInfo.getList()) { |
| | | platform.setGpsSubscribe(subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId()) != null); |
| | | platform.setCatalogSubscribe(subscribeHolder.getCatalogSubscribe(platform.getServerGBId()) != null); |
| | | } |
| | | } |
| | | return parentPlatformPageInfo; |
| | | } |
| | | |
| | | /** |
| | |
| | | storager.stopPlay(deviceId, channelId); |
| | | return result; |
| | | } |
| | | cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), (event) -> { |
| | | cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), null, (event) -> { |
| | | redisCatchStorage.stopPlay(streamInfo); |
| | | storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| | | RequestMessage msg = new RequestMessage(); |
| | |
| | | public ResponseEntity<String> playConvert(@PathVariable String streamId) { |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); |
| | | if (streamInfo == null) { |
| | | streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); |
| | | streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); |
| | | } |
| | | if (streamInfo == null) { |
| | | logger.warn("视频转码API调用失败!, 视频流已经停止!"); |
| | |
| | | package com.genersoft.iot.vmp.vmanager.gb28181.playback; |
| | | |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | |
| | | } |
| | | resultHolder.put(key, uuid, result); |
| | | Device device = storager.queryVideoDevice(deviceId); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId); |
| | | if (streamInfo != null) { |
| | | // 停止之前的下载 |
| | | cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream()); |
| | | } |
| | | |
| | | MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); |
| | | if (newMediaServerItem == null) { |
| | |
| | | |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); |
| | | |
| | | cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (MediaServerItem mediaServerItem, JSONObject response) -> { |
| | | logger.info("收到订阅消息: " + response.toJSONString()); |
| | | playService.onPublishHandlerForDownload(mediaServerItem, response, deviceId, channelId, uuid); |
| | | cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (InviteStreamInfo inviteStreamInfo) -> { |
| | | logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString()); |
| | | playService.onPublishHandlerForDownload(inviteStreamInfo, deviceId, channelId, uuid); |
| | | }, event -> { |
| | | RequestMessage msg = new RequestMessage(); |
| | | msg.setId(uuid); |
| | |
| | | @GetMapping("/stop/{deviceId}/{channelId}/{stream}") |
| | | public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { |
| | | |
| | | cmder.streamByeCmd(deviceId, channelId, stream); |
| | | cmder.streamByeCmd(deviceId, channelId, stream, null); |
| | | |
| | | if (logger.isDebugEnabled()) { |
| | | logger.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId)); |
| | |
| | | logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); |
| | | } |
| | | |
| | | DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, wvpResult->{ |
| | | DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, null, wvpResult->{ |
| | | resultHolder.invokeResult(wvpResult.getData()); |
| | | }); |
| | | |
| | |
| | | @PathVariable String channelId, |
| | | @PathVariable String stream) { |
| | | |
| | | cmder.streamByeCmd(deviceId, channelId, stream); |
| | | cmder.streamByeCmd(deviceId, channelId, stream, null); |
| | | |
| | | if (logger.isDebugEnabled()) { |
| | | logger.debug(String.format("设备录像回放停止 API调用,deviceId/channelId:%s/%s", deviceId, channelId)); |
| | |
| | | public ResponseEntity<String> playPause(@PathVariable String streamId) { |
| | | logger.info("playPause: "+streamId); |
| | | JSONObject json = new JSONObject(); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); |
| | | if (null == streamInfo) { |
| | | json.put("msg", "streamId不存在"); |
| | | logger.warn("streamId不存在!"); |
| | |
| | | public ResponseEntity<String> playResume(@PathVariable String streamId) { |
| | | logger.info("playResume: "+streamId); |
| | | JSONObject json = new JSONObject(); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); |
| | | if (null == streamInfo) { |
| | | json.put("msg", "streamId不存在"); |
| | | logger.warn("streamId不存在!"); |
| | |
| | | public ResponseEntity<String> playSeek(@PathVariable String streamId, @PathVariable long seekTime) { |
| | | logger.info("playSeek: "+streamId+", "+seekTime); |
| | | JSONObject json = new JSONObject(); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); |
| | | if (null == streamInfo) { |
| | | json.put("msg", "streamId不存在"); |
| | | logger.warn("streamId不存在!"); |
| | |
| | | public ResponseEntity<String> playSpeed(@PathVariable String streamId, @PathVariable Double speed) { |
| | | logger.info("playSpeed: "+streamId+", "+speed); |
| | | JSONObject json = new JSONObject(); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); |
| | | StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); |
| | | if (null == streamInfo) { |
| | | json.put("msg", "streamId不存在"); |
| | | logger.warn("streamId不存在!"); |
| | |
| | | result.put("error","未找到流信息"); |
| | | return result; |
| | | } |
| | | cmder.streamByeCmd(serial, code, streamInfo.getStream()); |
| | | cmder.streamByeCmd(serial, code, streamInfo.getStream(), null); |
| | | redisCatchStorage.stopPlay(streamInfo); |
| | | storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); |
| | | return null; |
| | |
| | | </div> |
| | | <!--设备列表--> |
| | | <el-table :data="platformList" border style="width: 100%" :height="winHeight"> |
| | | <el-table-column prop="name" label="名称" width="240" align="center"></el-table-column> |
| | | <el-table-column prop="name" label="名称" align="center"></el-table-column> |
| | | <el-table-column prop="serverGBId" label="平台编号" width="180" align="center"></el-table-column> |
| | | <el-table-column label="是否启用" width="120" align="center"> |
| | | <template slot-scope="scope"> |
| | |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="deviceGBId" label="设备国标编号" width="240" align="center"></el-table-column> |
| | | <el-table-column prop="deviceGBId" label="设备国标编号" width="200" align="center"></el-table-column> |
| | | <el-table-column prop="transport" label="信令传输模式" width="120" align="center"></el-table-column> |
| | | <el-table-column prop="channelCount" label="通道数" align="center"></el-table-column> |
| | | <el-table-column prop="channelCount" label="通道数" width="120" align="center"></el-table-column> |
| | | <el-table-column label="订阅信息" width="240" align="center" fixed="right"> |
| | | <template slot-scope="scope"> |
| | | <i v-if="scope.row.alarmSubscribe" style="font-size: 1.5rem;" title="报警订阅" class="subscribe-on iconfont icon-gbaojings" ></i> |
| | | <i v-if="!scope.row.alarmSubscribe" style="font-size: 1.5rem;" title="报警订阅" class="subscribe-off iconfont icon-gbaojings" ></i> |
| | | <i v-if="scope.row.catalogSubscribe" title="目录订阅" class="subscribe-on iconfont icon-gjichus" ></i> |
| | | <i v-if="!scope.row.catalogSubscribe" title="目录订阅" class="subscribe-off iconfont icon-gjichus" ></i> |
| | | <i v-if="scope.row.gpsSubscribe" title="位置订阅" class="subscribe-on iconfont icon-gxunjians" ></i> |
| | | <i v-if="!scope.row.gpsSubscribe" title="位置订阅" class="subscribe-off iconfont icon-gxunjians" ></i> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column label="操作" width="300" align="center" fixed="right"> |
| | | <template slot-scope="scope"> |
| | |
| | | } |
| | | }; |
| | | </script> |
| | | <style> |
| | | .subscribe-on{ |
| | | color: #409EFF; |
| | | font-size: 1.3rem; |
| | | } |
| | | .subscribe-off{ |
| | | color: #afafb3; |
| | | font-size: 1.3rem; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div id="chooseChannelForGb" > |
| | | <div style="font-size: 17px; color: #606060; white-space: nowrap; line-height: 30px; font-family: monospace;"> |
| | | <span v-if="catalogId == null">{{catalogName}}的直播流</span> |
| | | <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的直播流</span> |
| | | <span v-if="catalogId == null">{{catalogName}}的国标通道</span> |
| | | <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的国标通道</span> |
| | | </div> |
| | | <div style="background-color: #FFFFFF; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> |
| | | 搜索: <el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字" prefix-icon="el-icon-search" v-model="searchSrt" clearable> </el-input> |
| | |
| | | <template> |
| | | <div id="chooseChannelFoStream" > |
| | | <div style="font-size: 17px; color: #606060; white-space: nowrap; line-height: 30px; font-family: monospace;"> |
| | | <span v-if="catalogId == null">{{catalogName}}的直播流</span> |
| | | <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的直播流</span> |
| | | <span v-if="catalogId == null">{{catalogName}}的直播通道</span> |
| | | <span v-if="catalogId != null">{{catalogName}}({{catalogId}})的直播通道</span> |
| | | </div> |
| | | <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> |
| | | |
| | |
| | | @font-face { |
| | | font-family: "iconfont"; /* Project id 1291092 */ |
| | | src: url('iconfont.woff2?t=1644809302709') format('woff2'), |
| | | url('iconfont.woff?t=1644809302709') format('woff'), |
| | | url('iconfont.ttf?t=1644809302709') format('truetype'); |
| | | src: url('iconfont.woff2?t=1647245982270') format('woff2'), |
| | | url('iconfont.woff?t=1647245982270') format('woff'), |
| | | url('iconfont.ttf?t=1647245982270') format('truetype'); |
| | | } |
| | | |
| | | .iconfont { |
| | |
| | | -moz-osx-font-smoothing: grayscale; |
| | | } |
| | | |
| | | .icon-xitongxinxi:before { |
| | | content: "\e7d6"; |
| | | } |
| | | |
| | | .icon-gbaojings:before { |
| | | content: "\e7d7"; |
| | | } |
| | | |
| | | .icon-gjichus:before { |
| | | content: "\e7d8"; |
| | | } |
| | | |
| | | .icon-gxunjians:before { |
| | | content: "\e7d9"; |
| | | } |
| | | |
| | | .icon-ziyuan:before { |
| | | content: "\e7d5"; |
| | | } |