From 5a75381a00a555443925bbbd8e333b14473b3ed1 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: 星期二, 17 十月 2023 15:34:01 +0800 Subject: [PATCH] 基于新的云端录像结构实现国标录像 --- src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java | 84 +++++++ src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java | 65 +++-- src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java | 12 + src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java | 30 ++ src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java | 180 ++++++++++++--- src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java | 11 - src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java | 2 src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java | 50 +++ src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java | 27 ++ src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java | 35 +- src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java | 3 web_src/src/components/dialog/recordDownload.vue | 8 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java | 95 -------- web_src/src/components/CloudRecordDetail.vue | 14 14 files changed, 404 insertions(+), 212 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java index c46e38a..f657324 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -75,6 +75,33 @@ return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); } + public SsrcTransaction getSsrcTransactionByCallId(String callId){ + + if (ObjectUtils.isEmpty(callId)) { + return null; + } + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_" + callId+ "_*"; + List<Object> scanResult = RedisUtil.scan(redisTemplate, key); + if (!scanResult.isEmpty()) { + return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); + }else { + key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_play_*"; + scanResult = RedisUtil.scan(redisTemplate, key); + if (scanResult.isEmpty()) { + return null; + } + for (Object keyObj : scanResult) { + SsrcTransaction ssrcTransaction = (SsrcTransaction)redisTemplate.opsForValue().get(keyObj); + if (ssrcTransaction.getSipTransactionInfo() != null && + ssrcTransaction.getSipTransactionInfo().getCallId().equals(callId)) { + return ssrcTransaction; + } + } + return null; + } + + } + public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){ if (ObjectUtils.isEmpty(deviceId)) { deviceId ="*"; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java index b6aac9c..3900983 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java @@ -31,6 +31,7 @@ import javax.sip.message.Response; import java.text.ParseException; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -149,7 +150,7 @@ }else { // 鍙兘鏄澶囧彂閫佺殑鍋滄 - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransactionByCallId(callIdHeader.getCallId()); if (ssrcTransaction == null) { return; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java index 7d94787..41a7dd8 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java @@ -76,7 +76,7 @@ RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { - logger.info("[蹇冭烦] 璁惧{}鍦板潃鍙樺寲, 杩滅▼鍦板潃涓�: {}:{}", device.getDeviceId(), remoteAddressInfo.getIp(), remoteAddressInfo.getPort()); + logger.info("[鏀跺埌蹇冭烦] 璁惧{}鍦板潃鍙樺寲, 杩滅▼鍦板潃涓�: {}:{}", device.getDeviceId(), remoteAddressInfo.getIp(), remoteAddressInfo.getPort()); device.setPort(remoteAddressInfo.getPort()); device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); device.setIp(remoteAddressInfo.getIp()); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java index cf71bf1..f018eae 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java @@ -9,12 +9,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; import java.io.IOException; import java.net.ConnectException; +import java.net.SocketTimeoutException; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.TimeUnit; @Component public class AssistRESTfulUtils { @@ -22,21 +26,43 @@ private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class); + private OkHttpClient client; + + + + public interface RequestCallback{ void run(JSONObject response); } private OkHttpClient getClient(){ - OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); - if (logger.isDebugEnabled()) { - HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> { - logger.debug("http璇锋眰鍙傛暟锛�" + message); - }); - logging.setLevel(HttpLoggingInterceptor.Level.BASIC); - // OkHttp閫茶娣诲姞鏀旀埅鍣╨oggingInterceptor - httpClientBuilder.addInterceptor(logging); + return getClient(null); + } + + private OkHttpClient getClient(Integer readTimeOut){ + if (client == null) { + if (readTimeOut == null) { + readTimeOut = 10; + } + OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); + // 璁剧疆杩炴帴瓒呮椂鏃堕棿 + httpClientBuilder.connectTimeout(8, TimeUnit.SECONDS); + // 璁剧疆璇诲彇瓒呮椂鏃堕棿 + httpClientBuilder.readTimeout(readTimeOut,TimeUnit.SECONDS); + // 璁剧疆杩炴帴姹� + httpClientBuilder.connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES)); + if (logger.isDebugEnabled()) { + HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> { + logger.debug("http璇锋眰鍙傛暟锛�" + message); + }); + logging.setLevel(HttpLoggingInterceptor.Level.BASIC); + // OkHttp閫茶娣诲姞鏀旀埅鍣╨oggingInterceptor + httpClientBuilder.addInterceptor(logging); + } + client = httpClientBuilder.build(); } - return httpClientBuilder.build(); + return client; + } @@ -124,13 +150,91 @@ return responseJSON; } + public JSONObject sendPost(MediaServerItem mediaServerItem, String api, JSONObject param, ZLMRESTfulUtils.RequestCallback callback, Integer readTimeOut) { + OkHttpClient client = getClient(readTimeOut); - public JSONObject fileDuration(MediaServerItem mediaServerItem, String app, String stream, RequestCallback callback){ - Map<String, Object> param = new HashMap<>(); - param.put("app",app); - param.put("stream",stream); - param.put("recordIng",true); - return sendGet(mediaServerItem, "api/record/file/duration",param, callback); + if (mediaServerItem == null) { + return null; + } + String url = String.format("http://%s:%s/%s", mediaServerItem.getIp(), mediaServerItem.getRecordAssistPort(), api); + JSONObject responseJSON = new JSONObject(); + //-2鑷畾涔夋祦濯掍綋 璋冪敤閿欒鐮� + responseJSON.put("code",-2); + responseJSON.put("msg","ASSIST璋冪敤澶辫触"); + + RequestBody requestBodyJson = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), param.toString()); + + Request request = new Request.Builder() + .post(requestBodyJson) + .url(url) + .addHeader("Content-Type", "application/json") + .build(); + if (callback == null) { + try { + Response response = client.newCall(request).execute(); + if (response.isSuccessful()) { + ResponseBody responseBody = response.body(); + if (responseBody != null) { + String responseStr = responseBody.string(); + responseJSON = JSON.parseObject(responseStr); + } + }else { + response.close(); + Objects.requireNonNull(response.body()).close(); + } + }catch (IOException e) { + logger.error(String.format("[ %s ]ASSIST璇锋眰澶辫触: %s", url, e.getMessage())); + + if(e instanceof SocketTimeoutException){ + //璇诲彇瓒呮椂瓒呮椂寮傚父 + logger.error(String.format("璇诲彇ASSIST鏁版嵁澶辫触: %s, %s", url, e.getMessage())); + } + if(e instanceof ConnectException){ + //鍒ゆ柇杩炴帴寮傚父锛屾垜杩欓噷鏄姤Failed to connect to 10.7.5.144 + logger.error(String.format("杩炴帴ASSIST澶辫触: %s, %s", url, e.getMessage())); + } + + }catch (Exception e){ + logger.error(String.format("璁块棶ASSIST澶辫触: %s, %s", url, e.getMessage())); + } + }else { + client.newCall(request).enqueue(new Callback(){ + + @Override + public void onResponse(@NotNull Call call, @NotNull Response response){ + if (response.isSuccessful()) { + try { + String responseStr = Objects.requireNonNull(response.body()).string(); + callback.run(JSON.parseObject(responseStr)); + } catch (IOException e) { + logger.error(String.format("[ %s ]璇锋眰澶辫触: %s", url, e.getMessage())); + } + + }else { + response.close(); + Objects.requireNonNull(response.body()).close(); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + logger.error(String.format("杩炴帴ZLM澶辫触: %s, %s", call.request().toString(), e.getMessage())); + + if(e instanceof SocketTimeoutException){ + //璇诲彇瓒呮椂瓒呮椂寮傚父 + logger.error(String.format("璇诲彇ZLM鏁版嵁澶辫触: %s, %s", call.request().toString(), e.getMessage())); + } + if(e instanceof ConnectException){ + //鍒ゆ柇杩炴帴寮傚父锛屾垜杩欓噷鏄姤Failed to connect to 10.7.5.144 + logger.error(String.format("杩炴帴ZLM澶辫触: %s, %s", call.request().toString(), e.getMessage())); + } + } + }); + } + + + + return responseJSON; } public JSONObject getInfo(MediaServerItem mediaServerItem, RequestCallback callback){ @@ -138,33 +242,33 @@ return sendGet(mediaServerItem, "api/record/info",param, callback); } - public JSONObject addStreamCallInfo(MediaServerItem mediaServerItem, String app, String stream, String callId, RequestCallback callback){ - Map<String, Object> param = new HashMap<>(); - param.put("app",app); - param.put("stream",stream); - param.put("callId",callId); - return sendGet(mediaServerItem, "api/record/addStreamCallInfo",param, callback); + public JSONObject addTask(MediaServerItem mediaServerItem, String app, String stream, String startTime, + String endTime, String callId, List<String> filePathList, String remoteHost) { + + JSONObject videoTaskInfoJSON = new JSONObject(); + videoTaskInfoJSON.put("app", app); + videoTaskInfoJSON.put("stream", stream); + videoTaskInfoJSON.put("startTime", startTime); + videoTaskInfoJSON.put("endTime", endTime); + videoTaskInfoJSON.put("callId", callId); + videoTaskInfoJSON.put("filePathList", filePathList); + if (!ObjectUtils.isEmpty(remoteHost)) { + videoTaskInfoJSON.put("remoteHost", remoteHost); + } + + return sendPost(mediaServerItem, "api/record/file/download/task/add", videoTaskInfoJSON, null, 30); } - public JSONObject getDateList(MediaServerItem mediaServerItem, String app, String stream, int year, int month) { + public JSONObject queryTaskList(MediaServerItem mediaServerItem, String taskId, Boolean isEnd) { Map<String, Object> param = new HashMap<>(); - param.put("app", app); - param.put("stream", stream); - param.put("year", year); - param.put("month", month); - return sendGet(mediaServerItem, "api/record/date/list", param, null); - } + if (!ObjectUtils.isEmpty(taskId)) { + param.put("taskId", taskId); + } + if (!ObjectUtils.isEmpty(isEnd)) { + param.put("isEnd", isEnd); + } - public JSONObject getFileList(MediaServerItem mediaServerItem, int page, int count, String app, String stream, - String startTime, String endTime) { - Map<String, Object> param = new HashMap<>(); - param.put("app", app); - param.put("stream", stream); - param.put("page", page); - param.put("count", count); - param.put("startTime", startTime); - param.put("endTime", endTime); - return sendGet(mediaServerItem, "api/record/file/listWithDate", param, null); + return sendGet(mediaServerItem, "api/record/file/download/task/list", param, null); } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index 045bd7e..e385ad7 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -234,12 +234,6 @@ streamAuthorityInfo.setSign(sign); // 閴存潈閫氳繃 redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); - // 閫氱煡assist鏂扮殑callId - if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) { - taskExecutor.execute(() -> { - assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); - }); - } } } else { zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId()); @@ -267,15 +261,28 @@ } // 鏇挎崲娴佸湴鍧� if ("rtp".equals(param.getApp()) && !mediaInfo.isRtpEnable()) { - String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));; - InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); - if (inviteInfo != null) { - result.setStream_replace(inviteInfo.getStream()); - logger.info("[ZLM HOOK]鎺ㄦ祦閴存潈 stream: {} 鏇挎崲涓� {}", param.getStream(), inviteInfo.getStream()); + if (!mediaInfo.isRtpEnable()) { + String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));; + InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); + if (inviteInfo != null) { + result.setStream_replace(inviteInfo.getStream()); + logger.info("[ZLM HOOK]鎺ㄦ祦閴存潈 stream: {} 鏇挎崲涓� {}", param.getStream(), inviteInfo.getStream()); + } } + } + List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { + + // 涓哄綍鍒跺浗鏍囨ā鎷熶竴涓壌鏉冧俊鎭� + StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); + streamAuthorityInfo.setApp(param.getApp()); + streamAuthorityInfo.setStream(ssrcTransactionForAll.get(0).getStream()); + streamAuthorityInfo.setCallId(ssrcTransactionForAll.get(0).getSipTransactionInfo().getCallId()); + + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), ssrcTransactionForAll.get(0).getStream(), streamAuthorityInfo); + String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); String channelId = ssrcTransactionForAll.get(0).getChannelId(); DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); @@ -349,13 +356,11 @@ List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); // TODO 閲嶆瀯姝ゅ閫昏緫 - boolean isPush = false; if (param.isRegist()) { - // 澶勭悊娴佹敞鍐岀殑閴存潈淇℃伅 + // 澶勭悊娴佹敞鍐岀殑閴存潈淇℃伅锛� 娴佹敞閿�杩欓噷涓嶅啀鍒犻櫎閴存潈淇℃伅锛屼笅娆℃潵浜嗘柊鐨勯壌鏉冧俊鎭細瀵瑰氨鐨勮繘琛岃鐩� if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { - isPush = true; StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); if (streamAuthorityInfo == null) { streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); @@ -365,8 +370,6 @@ } redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); } - } else { - redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); } if ("rtsp".equals(param.getSchema())) { diff --git a/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java b/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java index e353c7a..5a5eb65 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java @@ -1,5 +1,7 @@ package com.genersoft.iot.vmp.service; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; import com.genersoft.iot.vmp.service.bean.CloudRecordItem; @@ -28,4 +30,14 @@ */ List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems); + /** + * 娣诲姞鍚堝苟浠诲姟 + */ + String addTask(String app, String stream, String mediaServerId, String startTime, String endTime, String callId, String remoteHost); + + + /** + * 鏌ヨ鍚堝苟浠诲姟鍒楄〃 + */ + JSONArray queryTask(String taskId, String mediaServerId, Boolean isEnd); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java index 8cfdd88..c5f1196 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java @@ -87,21 +87,10 @@ void updateMediaServerKeepalive(String mediaServerId, ServerKeepaliveData data); - boolean checkRtpServer(MediaServerItem mediaServerItem, String rtp, String stream); - /** * 鑾峰彇璐熻浇淇℃伅 * @return */ MediaServerLoad getLoad(MediaServerItem mediaServerItem); - /** - * 鎸夋椂闂存煡鎵惧綍鍍忔枃浠� - */ - List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems); - - /** - * 鏌ユ壘瀛樺湪褰曞儚鏂囦欢鐨勬椂闂� - */ - List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java index d9f5189..1d8a537 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java @@ -1,11 +1,17 @@ package com.genersoft.iot.vmp.service.impl; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.GbStream; +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; +import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; import com.genersoft.iot.vmp.service.ICloudRecordService; +import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.bean.CloudRecordItem; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; @@ -32,7 +38,16 @@ private CloudRecordServiceMapper cloudRecordServiceMapper; @Autowired + private IMediaServerService mediaServerService; + + @Autowired private IRedisCatchStorage redisCatchStorage; + + @Autowired + private AssistRESTfulUtils assistRESTfulUtils; + + @Autowired + private VideoStreamSessionManager streamSession; @Override public PageInfo<CloudRecordItem> getList(int page, int count, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { @@ -54,7 +69,8 @@ } PageHelper.startPage(page, count); - List<CloudRecordItem> all = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, endTimeStamp, mediaServerItems); + List<CloudRecordItem> all = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, endTimeStamp, + null, mediaServerItems); return new PageInfo<>(all); } @@ -69,7 +85,8 @@ } long startTimeStamp = startDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); long endTimeStamp = endDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); - List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, endTimeStamp, mediaServerItems); + List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, + endTimeStamp, null, mediaServerItems); if (cloudRecordItemList.isEmpty()) { return new ArrayList<>(); } @@ -83,12 +100,71 @@ @Override public void addRecord(OnRecordMp4HookParam param) { - CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param); + CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param); StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); if (streamAuthorityInfo != null) { cloudRecordItem.setCallId(streamAuthorityInfo.getCallId()); } - logger.info("[娣诲姞褰曞儚璁板綍] {}/{} 鏂囦欢澶у皬锛歿}", param.getApp(), param.getStream(), param.getFile_size()); + logger.info("[娣诲姞褰曞儚璁板綍] {}/{} 鏂囦欢澶у皬锛歿}, 鏃堕暱锛� {}绉�", param.getApp(), param.getStream(), param.getFile_size(),param.getTime_len()); cloudRecordServiceMapper.add(cloudRecordItem); } + + @Override + public String addTask(String app, String stream, String mediaServerId, String startTime, String endTime, String callId, String remoteHost) { + // 鍙傛暟鏍¢獙 + assert app != null; + assert stream != null; + MediaServerItem mediaServerItem = null; + if (mediaServerId == null) { + mediaServerItem = mediaServerService.getDefaultMediaServer(); + }else { + mediaServerItem = mediaServerService.getOne(mediaServerId); + } + if (mediaServerItem == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒板彲鐢ㄧ殑娴佸獟浣�"); + }else { + if (remoteHost == null) { + remoteHost = "http://" + mediaServerItem.getStreamIp() + ":" + mediaServerItem.getRecordAssistPort(); + } + } + Long startTimeStamp = null; + Long endTimeStamp = null; + if (startTime != null) { + startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); + } + if (endTime != null) { + endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); + } + + List<MediaServerItem> mediaServers = new ArrayList<>(); + mediaServers.add(mediaServerItem); + // 妫�绱㈢浉鍏崇殑褰曞儚鏂囦欢 + List<String> filePathList = cloudRecordServiceMapper.queryRecordFilePathList(app, stream, startTimeStamp, endTimeStamp, callId, mediaServers); + if (filePathList == null || filePathList.isEmpty()) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈绱㈠埌瑙嗛鏂囦欢"); + } + JSONObject result = assistRESTfulUtils.addTask(mediaServerItem, app, stream, startTime, endTime, callId, filePathList, remoteHost); + if (result.getInteger("code") != 0) { + throw new ControllerException(result.getInteger("code"), result.getString("msg")); + } + return result.getString("data"); + } + + @Override + public JSONArray queryTask(String taskId, String mediaServerId, Boolean isEnd) { + MediaServerItem mediaServerItem = null; + if (mediaServerId == null) { + mediaServerItem = mediaServerService.getDefaultMediaServer(); + }else { + mediaServerItem = mediaServerService.getOne(mediaServerId); + } + if (mediaServerItem == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒板彲鐢ㄧ殑娴佸獟浣�"); + } + JSONObject result = assistRESTfulUtils.queryTaskList(mediaServerItem, taskId, isEnd); + if (result.getInteger("code") != 0) { + throw new ControllerException(result.getInteger("code"), result.getString("msg")); + } + return result.getJSONArray("data"); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java index 4c149d4..4759d3a 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java @@ -742,15 +742,6 @@ } @Override - public boolean checkRtpServer(MediaServerItem mediaServerItem, String app, String stream) { - JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, stream); - if(rtpInfo.getInteger("code") == 0){ - return rtpInfo.getBoolean("exist"); - } - return false; - } - - @Override public MediaServerLoad getLoad(MediaServerItem mediaServerItem) { MediaServerLoad result = new MediaServerLoad(); result.setId(mediaServerItem.getId()); @@ -760,91 +751,5 @@ result.setGbReceive(inviteStreamService.getStreamInfoCount(mediaServerItem.getId())); result.setGbSend(redisCatchStorage.getGbSendCount(mediaServerItem.getId())); return result; - } - - @Override - public List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { - Assert.notNull(app, "app涓嶅瓨鍦�"); - Assert.notNull(stream, "stream涓嶅瓨鍦�"); - Assert.notNull(startTime, "startTime涓嶅瓨鍦�"); - Assert.notNull(endTime, "endTime涓嶅瓨鍦�"); - Assert.notEmpty(mediaServerItems, "娴佸獟浣撳垪琛ㄤ负绌�"); - - CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; - for (int i = 0; i < mediaServerItems.size(); i++) { - completableFutures[i] = getRecordFilesForOne(app, stream, startTime, endTime, mediaServerItems.get(i)); - } - List<RecordFile> result = new ArrayList<>(); - for (int i = 0; i < completableFutures.length; i++) { - try { - List<RecordFile> list = (List<RecordFile>) completableFutures[i].get(); - if (!list.isEmpty()) { - for (int g = 0; g < list.size(); g++) { - list.get(g).setMediaServerId(mediaServerItems.get(i).getId()); - } - result.addAll(list); - } - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throw new RuntimeException(e); - } - } - Comparator<RecordFile> comparator = Comparator.comparing(RecordFile::getFileName); - result.sort(comparator); - return result; - } - - @Override - public List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) { - Assert.notNull(app, "app涓嶅瓨鍦�"); - Assert.notNull(stream, "stream涓嶅瓨鍦�"); - Assert.notEmpty(mediaServerItems, "娴佸獟浣撳垪琛ㄤ负绌�"); - CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; - - for (int i = 0; i < mediaServerItems.size(); i++) { - completableFutures[i] = getRecordDatesForOne(app, stream, year, month, mediaServerItems.get(i)); - } - List<String> result = new ArrayList<>(); - CompletableFuture.allOf(completableFutures).join(); - for (CompletableFuture completableFuture : completableFutures) { - try { - List<String> list = (List<String>) completableFuture.get(); - result.addAll(list); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throw new RuntimeException(e); - } - } - Collections.sort(result); - return result; - } - - @Async - public CompletableFuture<List<String>> getRecordDatesForOne(String app, String stream, int year, int month, MediaServerItem mediaServerItem) { - JSONObject fileListJson = assistRESTfulUtils.getDateList(mediaServerItem, app, stream, year, month); - if (fileListJson != null && !fileListJson.isEmpty()) { - if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { - JSONArray data = fileListJson.getJSONArray("data"); - return CompletableFuture.completedFuture(data.toJavaList(String.class)); - } - } - return CompletableFuture.completedFuture(new ArrayList<>()); - } - - @Async - public CompletableFuture<List<RecordFile>> getRecordFilesForOne(String app, String stream, String startTime, String endTime, MediaServerItem mediaServerItem) { - JSONObject fileListJson = assistRESTfulUtils.getFileList(mediaServerItem, 1, 100000000, app, stream, startTime, endTime); - if (fileListJson != null && !fileListJson.isEmpty()) { - if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { - JSONObject data = fileListJson.getJSONObject("data"); - JSONArray list = data.getJSONArray("list"); - if (list != null) { - return CompletableFuture.completedFuture(list.toJavaList(RecordFile.class)); - } - } - } - return CompletableFuture.completedFuture(new ArrayList<>()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index f2653f7..eb9e2ef 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -27,11 +27,13 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.service.*; +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import gov.nist.javax.sip.message.SIPResponse; @@ -106,6 +108,9 @@ @Autowired private ZlmHttpHookSubscribe subscribe; + + @Autowired + private CloudRecordServiceMapper cloudRecordServiceMapper; @Override @@ -749,31 +754,43 @@ logger.warn("鏌ヨ褰曞儚淇℃伅鏃跺彂鐜拌妭鐐瑰凡绂荤嚎"); return null; } - if (mediaServerItem.getRecordAssistPort() > 0) { - JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream(), null); - if (jsonObject == null) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "杩炴帴Assist鏈嶅姟澶辫触"); - } - if (jsonObject.getInteger("code") == 0) { - long duration = jsonObject.getLong("data"); - - if (duration == 0) { - inviteInfo.getStreamInfo().setProgress(0); - } else { - String startTime = inviteInfo.getStreamInfo().getStartTime(); - String endTime = inviteInfo.getStreamInfo().getEndTime(); - long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); - long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); - - BigDecimal currentCount = new BigDecimal(duration / 1000); - BigDecimal totalCount = new BigDecimal(end - start); - BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP); - double process = divide.doubleValue(); - inviteInfo.getStreamInfo().setProgress(process); - } - inviteStreamService.updateInviteInfo(inviteInfo); - } + if (mediaServerItem.getRecordAssistPort() == 0) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈厤缃瓵ssist鏈嶅姟锛屾棤娉曞畬鎴愬綍鍍忎笅杞�"); } + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream); + + if (ssrcTransaction == null) { + logger.warn("[鑾峰彇涓嬭浇杩涘害]锛屾湭鎵惧埌涓嬭浇浜嬪姟淇℃伅"); + return null; + } + + // 涓轰簡鏀寔澶氫釜鏁版嵁搴擄紝杩欓噷涓嶈兘浣跨敤姹傚拰鍑芥暟鏉ョ洿鎺ヨ幏鍙栨�绘暟浜� + List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList("rtp", inviteInfo.getStream(), null, null, ssrcTransaction.getCallId(), null); + + if (cloudRecordItemList.isEmpty()) { + logger.warn("[鑾峰彇涓嬭浇杩涘害]锛屾湭鎵惧埌涓嬭浇瑙嗛淇℃伅"); + return null; + } + long duration = 0; + for (CloudRecordItem cloudRecordItem : cloudRecordItemList) { + duration += cloudRecordItem.getTimeLen(); + } + if (duration == 0) { + inviteInfo.getStreamInfo().setProgress(0); + } else { + String startTime = inviteInfo.getStreamInfo().getStartTime(); + String endTime = inviteInfo.getStreamInfo().getEndTime(); + long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); + long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); + + BigDecimal currentCount = new BigDecimal(duration); + BigDecimal totalCount = new BigDecimal(end - start); + BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP); + double process = divide.doubleValue(); + inviteInfo.getStreamInfo().setProgress(process); + } + inviteStreamService.updateInviteInfo(inviteInfo); + return inviteInfo.getStreamInfo(); } return null; diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java index 10595ef..d5a0859 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java @@ -42,17 +42,37 @@ @Select(" <script>" + "select * " + - "from wvp_cloud_record " + - "where 0 = 0" + + " from wvp_cloud_record " + + " where 0 = 0" + " <if test= 'app != null '> and app=#{app}</if>" + " <if test= 'stream != null '> and stream=#{stream}</if>" + - " <if test= 'startTimeStamp != null '> and start_time >= #{startTimeStamp}</if>" + - " <if test= 'endTimeStamp != null '> and end_time <= #{endTimeStamp}</if>" + + " <if test= 'startTimeStamp != null '> and end_time >= #{startTimeStamp}</if>" + + " <if test= 'endTimeStamp != null '> and start_time <= #{endTimeStamp}</if>" + + " <if test= 'callId != null '> and call_id = #{callId}</if>" + " <if test= 'mediaServerItemList != null ' > and media_server_id in " + " <foreach collection='mediaServerItemList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" + " </if>" + " </script>") List<CloudRecordItem> getList(@Param("app") String app, @Param("stream") String stream, @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp, - List<MediaServerItem> mediaServerItemList); + @Param("callId")String callId, List<MediaServerItem> mediaServerItemList); + + + @Select(" <script>" + + "select file_path" + + " from wvp_cloud_record " + + " where 0 = 0" + + " <if test= 'app != null '> and app=#{app}</if>" + + " <if test= 'stream != null '> and stream=#{stream}</if>" + + " <if test= 'startTimeStamp != null '> and end_time >= #{startTimeStamp}</if>" + + " <if test= 'endTimeStamp != null '> and start_time <= #{endTimeStamp}</if>" + + " <if test= 'callId != null '> and call_id = #{callId}</if>" + + " <if test= 'mediaServerItemList != null ' > and media_server_id in " + + " <foreach collection='mediaServerItemList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" + + " </if>" + + " </script>") + List<String> queryRecordFilePathList(@Param("app") String app, @Param("stream") String stream, + @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp, + @Param("callId")String callId, List<MediaServerItem> mediaServerItemList); + } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java index 0d79675..04778c3 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java @@ -1,5 +1,7 @@ package com.genersoft.iot.vmp.vmanager.cloudRecord; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; @@ -145,19 +147,53 @@ @Operation(summary = "娣诲姞鍚堝苟浠诲姟") @Parameter(name = "app", description = "搴旂敤鍚�", required = true) @Parameter(name = "stream", description = "娴両D", required = true) + @Parameter(name = "mediaServerId", description = "娴佸獟浣揑D", required = false) @Parameter(name = "startTime", description = "閴存潈ID", required = false) @Parameter(name = "endTime", description = "閴存潈ID", required = false) @Parameter(name = "callId", description = "閴存潈ID", required = false) @Parameter(name = "remoteHost", description = "杩斿洖鍦板潃鏃剁殑杩滅▼鍦板潃", required = false) public String addTask( - @RequestParam String app, - @RequestParam String stream, - @RequestParam String startTime, - @RequestParam String endTime, - @RequestParam String callId, - @RequestParam String remoteHost + @RequestParam(required = true) String app, + @RequestParam(required = true) String stream, + @RequestParam(required = false) String mediaServerId, + @RequestParam(required = false) String startTime, + @RequestParam(required = false) String endTime, + @RequestParam(required = false) String callId, + @RequestParam(required = false) String remoteHost ){ - return cloudRecordService.addTask(app, stream, startTime, endTime, callId, remoteHost); + return cloudRecordService.addTask(app, stream, mediaServerId, startTime, endTime, callId, remoteHost); + } + + @ResponseBody + @GetMapping("/task/list") + @Operation(summary = "鏌ヨ鍚堝苟浠诲姟") + @Parameter(name = "taskId", description = "浠诲姟Id", required = false) + @Parameter(name = "mediaServerId", description = "娴佸獟浣揑D", required = false) + @Parameter(name = "isEnd", description = "鏄惁缁撴潫", required = false) + public JSONArray queryTaskList( + @RequestParam(required = false) String taskId, + @RequestParam(required = false) String mediaServerId, + @RequestParam(required = false) Boolean isEnd + ){ + return cloudRecordService.queryTask(taskId, mediaServerId, isEnd); + } + + @ResponseBody + @GetMapping("/collect/add") + @Operation(summary = "娣诲姞鏀惰棌") + @Parameter(name = "app", description = "搴旂敤鍚�", required = true) + @Parameter(name = "stream", description = "娴両D", required = true) + @Parameter(name = "mediaServerId", description = "娴佸獟浣揑D", required = false) + @Parameter(name = "startTime", description = "閴存潈ID", required = false) + @Parameter(name = "endTime", description = "閴存潈ID", required = false) + @Parameter(name = "callId", description = "閴存潈ID", required = false) + @Parameter(name = "collectType", description = "鏀惰棌绫诲瀷", required = false) + public JSONArray addCollect( + @RequestParam(required = false) String taskId, + @RequestParam(required = false) String mediaServerId, + @RequestParam(required = false) Boolean isEnd + ){ + return cloudRecordService.queryTask(taskId, mediaServerId, isEnd); } diff --git a/web_src/src/components/CloudRecordDetail.vue b/web_src/src/components/CloudRecordDetail.vue index 207fbef..a3b1bc6 100755 --- a/web_src/src/components/CloudRecordDetail.vue +++ b/web_src/src/components/CloudRecordDetail.vue @@ -480,12 +480,13 @@ let that = this; this.$axios({ method: 'get', - url:`/record_proxy/${that.mediaServerId}/api/record/file/download/task/add`, + url:`/api/cloud/record/task/add`, params: { - app: that.app, - stream: that.stream, - startTime: moment(this.taskTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'), - endTime: moment(this.taskTimeRange[1]).format('YYYY-MM-DD HH:mm:ss'), + app: this.app, + stream: this.stream, + mediaServerId: this.mediaServerId, + startTime: moment(this.taskTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'), + endTime: moment(this.taskTimeRange[1]).format('YYYY-MM-DD HH:mm:ss'), } }).then(function (res) { if (res.data.code === 0 ) { @@ -505,8 +506,9 @@ let that = this; this.$axios({ method: 'get', - url:`/record_proxy/${that.mediaServerId}/api/record/file/download/task/list`, + url:`/api/cloud/record/task/list`, params: { + mediaServerId: this.mediaServerId, isEnd: isEnd, } }).then(function (res) { diff --git a/web_src/src/components/dialog/recordDownload.vue b/web_src/src/components/dialog/recordDownload.vue index 7a94540..95a512e 100755 --- a/web_src/src/components/dialog/recordDownload.vue +++ b/web_src/src/components/dialog/recordDownload.vue @@ -137,10 +137,11 @@ getFileDownload: function (){ this.$axios({ method: 'get', - url:`/record_proxy/${this.mediaServerId}/api/record/file/download/task/add`, + url:`/api/cloud/record/task/add`, params: { app: this.app, stream: this.stream, + mediaServerId: this.mediaServerId, startTime: null, endTime: null, } @@ -169,10 +170,9 @@ getProgressForFile: function (callback){ this.$axios({ method: 'get', - url:`/record_proxy/${this.mediaServerId}/api/record/file/download/task/list`, + url:`/api/cloud/record/task/list`, params: { - app: this.app, - stream: this.stream, + mediaServerId: this.mediaServerId, taskId: this.taskId, isEnd: true, } -- Gitblit v1.8.0