lipenghui 1 месяц назад
Родитель
Сommit
4703bdc19b

+ 25 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/yanfan/enums/CodeEnum.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.pms.controller.admin.yanfan.enums;
+
+public enum CodeEnum {
+    /**
+     * CodeEnum
+     */
+    SUCCESS(200, "成功"),
+    FAIL(500, "失败");
+
+    private final int code;
+    private final String msg;
+
+    CodeEnum(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 169 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/yanfan/sip/record/RecordController.java

@@ -0,0 +1,169 @@
+package cn.iocoder.yudao.module.pms.controller.admin.yanfan.sip.record;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils.BaseResult;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.enums.CodeEnum;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils.DataResult;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils.MessageUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils.WebAsyncUtil;
+import cn.iocoder.yudao.module.pms.service.yanfan.play.model.Stream;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.model.RecordItem;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.model.RecordList;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.record.IRecordService;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.context.request.async.WebAsyncTask;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Slf4j
+@RestController
+@RequestMapping("/sip/record")
+public class RecordController {
+
+    @Autowired
+    private IRecordService recordService;
+
+    @Qualifier("taskExecutor")
+    @Autowired
+    private ThreadPoolTaskExecutor taskExecutor;
+
+    @Operation(summary="设备录像查询")
+    //@PreAuthorize("@ss.hasPermi('iot:video:list')")
+    @GetMapping("/devquery/{deviceId}/{channelId}")
+    public WebAsyncTask<Object> devquery(@PathVariable String deviceId, @PathVariable String channelId, String start, String end) {
+        return WebAsyncUtil.init(taskExecutor, () -> {
+            try {
+                RecordList result = recordService.listDevRecord(deviceId, channelId, start, end);
+                return DataResult.out(CodeEnum.SUCCESS, result);
+            } catch (Exception e) {
+                log.error("", e);
+                return BaseResult.out(CodeEnum.FAIL, e.getMessage());
+            }
+        });
+    }
+
+    @Operation(summary="设备录像缓存查询")
+    //@PreAuthorize("@ss.hasPermi('iot:video:list')")
+    @GetMapping("/query/{channelId}/{sn}")
+    public CommonResult<List<RecordItem>> list(@PathVariable String channelId, @PathVariable String sn) {
+        return success(recordService.listRecord(channelId, sn));
+    }
+
+    @Operation(summary="指定流ID开始录像")
+    //@PreAuthorize("@ss.hasPermi('iot:video:list')")
+    @GetMapping("/start/{stream}")
+    public CommonResult<String> startRecord(@PathVariable String stream) {
+        boolean result = recordService.startRecord(stream);
+        if (result) {
+            return success("success");
+        } else {
+            return error(new ErrorCode(1,"error!"));
+        }
+    }
+
+    @Operation(summary="指定流ID停止录像")
+    //@PreAuthorize("@ss.hasPermi('iot:video:list')")
+    @GetMapping("/stop/{stream}")
+    public CommonResult<String> stopRecord(@PathVariable String stream) {
+        boolean result = recordService.stopRecord(stream);
+        if (result) {
+            return success(MessageUtils.message("success"));
+        } else {
+            return error(new ErrorCode(1,"error!"));
+        }
+    }
+
+    @Operation(summary="获取流对应的录像文件列表")
+    //@PreAuthorize("@ss.hasPermi('iot:video:list')")
+    @GetMapping("/file/{stream}/{period}")
+    public CommonResult<JSONObject> getMp4RecordFile(@PathVariable String stream, @PathVariable String period) {
+        return success(recordService.getMp4RecordFile(stream, period));
+    }
+
+    @Operation(summary="直播录像")
+    @GetMapping("/play/{deviceId}/{channelId}")
+    public CommonResult<Stream> playRecord(@PathVariable String deviceId, @PathVariable String channelId) {
+        log.debug("直播录像 API调用,deviceId:{},channelId:{}", deviceId, channelId);
+        return success(recordService.playRecord(deviceId, channelId));
+    }
+
+    //@PreAuthorize("@ss.hasPermi('iot:sip:record:download')")
+    @Operation(summary="设备录像下载")
+    @GetMapping("/download/{deviceId}/{channelId}")
+    public CommonResult<Stream> download(@PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime, String speed) {
+        log.debug("设备录像下载 API调用,deviceId:{},channelId:{},downloadSpeed:{}", deviceId, channelId, speed);
+        return success(recordService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(speed)));
+    }
+
+    //@PreAuthorize("@ss.hasPermi('iot:sip:record:upload')")
+//    @Operation(summary="录像上传OSS")
+//    @GetMapping("/upload")
+//    public AjaxResult upload(@RequestParam String recordApi, @RequestParam String file) {
+//        logger.debug(String.format("录像上传OSS API调用,recordApi:%s,file:%s", recordApi, file));
+//        return AjaxResult.success("success!", recordService.upload(recordApi, file));
+//    }
+
+    @Operation(summary="查询服务端录像列表")
+    //@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
+    @GetMapping("/serverRecord/list")
+    public CommonResult<Object> listServerRecord(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam String recordApi) {
+        try {
+            Object data = recordService.listServerRecord(recordApi, pageNum, pageSize);
+            return success(data);
+        } catch (Exception e) {
+            return error(new ErrorCode(2, e.getMessage()));
+        }
+    }
+
+    @Operation(summary="通过日期查询服务端录像列表")
+    //@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
+    @GetMapping("/serverRecord/date/list")
+    public CommonResult<JSONArray> listServerRecordByDate(@RequestParam(required = false) Integer year, @RequestParam(required = false) Integer month, @RequestParam String app, @RequestParam String stream, @RequestParam String recordApi) {
+        return success(recordService.listServerRecordByDate(recordApi, year, month, app, stream));
+    }
+
+    @Operation(summary="通过流ID查询服务端录像列表")
+    //@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
+    @GetMapping("/serverRecord/stream/list")
+    public CommonResult<JSONObject> listServerRecordByStream(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam String app, @RequestParam String recordApi) {
+        return success(recordService.listServerRecordByStream(recordApi, pageNum, pageSize, app));
+    }
+
+    @Operation(summary="通过应用名查询服务端录像列表")
+    //@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
+    @GetMapping("/serverRecord/app/list")
+    public CommonResult<JSONObject> listServerRecordByApp(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam String recordApi) {
+        return success(recordService.listServerRecordByApp(recordApi, pageNum, pageSize));
+    }
+
+    @Operation(summary="通过文件名查询服务端录像列表")
+    //@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
+    @GetMapping("/serverRecord/file/list")
+    public CommonResult<JSONObject> listServerRecordByFile(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam String app, @RequestParam String stream, @RequestParam String startTime, @RequestParam String endTime, @RequestParam String recordApi) {
+        return success(recordService.listServerRecordByFile(recordApi, pageNum, pageSize, app, stream, startTime, endTime));
+    }
+
+    @Operation(summary="通过设备信息查询服务端录像列表")
+    //@PreAuthorize("@ss.hasPermi('iot:sip:record:list')")
+    @GetMapping("/serverRecord/device/list")
+    public CommonResult<JSONObject> getServerRecordByDevice(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam String deviceId, @RequestParam String channelId, @RequestParam String startTime, @RequestParam String endTime) {
+        return success(recordService.listServerRecordByDevice(pageNum, pageSize, deviceId, channelId, startTime, endTime));
+    }
+
+    @Operation(summary="代理视频流rtsp转换hls.m3u8")
+    @GetMapping("/addStreamProxy/{deviceId}")
+    public CommonResult<JSONObject> addStreamProxy(@PathVariable String deviceId, @RequestParam String url, @RequestParam(required = false, defaultValue = "10") Integer count) {
+        return success(recordService.addStreamProxy(deviceId, url, count));
+    }
+}

+ 50 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/yanfan/utils/BaseResult.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils;
+
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.enums.CodeEnum;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class BaseResult implements Serializable {
+    private static final long serialVersionUID = 1383530376576722749L;
+    private int code;
+    private String msg;
+
+    protected BaseResult() {
+    }
+
+    protected BaseResult(CodeEnum codeEnum) {
+        this.code = codeEnum.getCode();
+        this.msg = codeEnum.getMsg();
+    }
+
+    protected BaseResult(CodeEnum codeEnum, String msg) {
+        this.code = codeEnum.getCode();
+        this.msg = msg;
+    }
+
+    public static BaseResult out(CodeEnum codeEnum) {
+        return new BaseResult(codeEnum);
+    }
+
+    public static BaseResult out(CodeEnum codeEnum, String msg) {
+        return new BaseResult(codeEnum, msg);
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+}

+ 52 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/yanfan/utils/DataResult.java

@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils;
+
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.enums.CodeEnum;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+public class DataResult<T> extends BaseResult implements Serializable {
+    private static final long serialVersionUID = -633787910682534734L;
+    private T data;
+
+    private DataResult() {
+
+    }
+
+    private DataResult(CodeEnum codeEnum, T data) {
+        super(codeEnum);
+        this.data = data;
+    }
+
+    public static <T> DataResult<T> out(CodeEnum codeEnum, T data) {
+        return new DataResult<>(codeEnum, data);
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        if (!super.equals(o)) {
+            return false;
+        }
+        DataResult<?> that = (DataResult<?>) o;
+        return Objects.equals(data, that.data);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), data);
+    }
+}

+ 170 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/yanfan/utils/RecordApiUtils.java

@@ -0,0 +1,170 @@
+package cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.springframework.stereotype.Component;
+
+import javax.validation.constraints.NotNull;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+@Slf4j
+@Component
+public class RecordApiUtils {
+    public interface RequestCallback {
+        void run(JSONObject response);
+    }
+
+    private OkHttpClient getClient() {
+        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
+        return httpClientBuilder.build();
+    }
+
+    public JSONObject sendGet(String recoreUrl, String api, Map<String, Object> param, RequestCallback callback) {
+        OkHttpClient client = getClient();
+        StringBuilder stringBuffer = new StringBuilder();
+        stringBuffer.append(String.format("%s/%s", recoreUrl, api));
+        JSONObject responseJSON = null;
+        if (param != null && param.keySet().size() > 0) {
+            stringBuffer.append("?");
+            int index = 1;
+            for (String key : param.keySet()) {
+                if (param.get(key) != null) {
+                    stringBuffer.append(key).append("=").append(param.get(key));
+                    if (index < param.size()) {
+                        stringBuffer.append("&");
+                    }
+                }
+                index++;
+            }
+        }
+        String url = stringBuffer.toString();
+        Request request = new Request.Builder()
+                .get()
+                .url(url)
+                .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 (ConnectException e) {
+                log.error(String.format("连接Assist失败: %s, %s", e.getCause().getMessage(), e.getMessage()));
+                log.error("请检查media配置并确认Assist已启动...");
+            } catch (IOException e) {
+                log.error(String.format("[ %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) {
+                            log.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) {
+                    log.error(String.format("连接Assist失败: %s, %s", e.getCause().getMessage(), e.getMessage()));
+                    log.info("请检查media配置并确认Assist已启动...");
+                }
+            });
+        }
+        return responseJSON;
+    }
+
+    public JSONObject fileDuration(String recoreUrl, 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(recoreUrl, "zlm/record//file/duration", param, callback);
+    }
+
+    public JSONObject getInfo(String recoreUrl, RequestCallback callback) {
+        Map<String, Object> param = new HashMap<>();
+        return sendGet(recoreUrl, "zlm/record//info", param, callback);
+    }
+
+    public JSONObject getRecordlist(String recoreUrl, Integer pageNum, Integer pageSize, RequestCallback callback) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("pageNum", pageNum);
+        param.put("pageSize", pageSize);
+        return sendGet(recoreUrl, "zlm/record/list", param, callback);
+    }
+
+    public JSONObject getRecordDatelist(String recoreUrl, Integer year, Integer month, String app, String stream, RequestCallback callback) {
+        Map<String, Object> param = new HashMap<>();
+        if(year != null) {
+            param.put("year", year);
+        }
+        if(year != null) {
+            param.put("month", month);
+        }
+        param.put("app", app);
+        param.put("stream", stream);
+        return sendGet(recoreUrl, "zlm/record/date/list", param, callback);
+    }
+
+    public JSONObject getRecordStreamlist(String recoreUrl, Integer pageNum, Integer pageSize, String app, RequestCallback callback) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("page", pageNum);
+        param.put("count", pageSize);
+        param.put("app", app);
+        return sendGet(recoreUrl, "zlm/record/stream/list", param, callback);
+    }
+
+    public JSONObject getRecordApplist(String recoreUrl, Integer pageNum, Integer pageSize, RequestCallback callback) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("page", pageNum);
+        param.put("count", pageSize);
+        return sendGet(recoreUrl, "zlm/record/app/list", param, callback);
+    }
+
+    public JSONObject getRecordFilelist(String recoreUrl, Integer pageNum, Integer pageSize, String app, String stream, String startTime, String endTime, RequestCallback callback) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("page", pageNum);
+        param.put("count", pageSize);
+        param.put("app", app);
+        param.put("stream", stream);
+        param.put("startTime", startTime);
+        param.put("endTime", endTime);
+        return sendGet(recoreUrl, "zlm/record/file/list", param, callback);
+    }
+
+    public JSONObject addStreamCallInfo(String recoreUrl, 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(recoreUrl, "zlm/record/addStreamCallInfo", param, callback);
+    }
+
+    public JSONObject uploadOss(String recoreUrl, String file, RequestCallback callback) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("resourcePath", file);
+        return sendGet(recoreUrl, "file/upload", param, callback);
+    }
+}

+ 23 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/yanfan/utils/WebAsyncUtil.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils;
+
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.enums.CodeEnum;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.web.context.request.async.WebAsyncTask;
+
+import java.util.concurrent.Callable;
+
+@Slf4j
+public class WebAsyncUtil {
+    public static final Long COMMON_TIMEOUT = 30000L;
+
+    public static WebAsyncTask<Object> init(ThreadPoolTaskExecutor executor, Callable<Object> callable) {
+        WebAsyncTask<Object> asyncTask = new WebAsyncTask<>(COMMON_TIMEOUT, executor, callable);
+
+        asyncTask.onCompletion(() -> log.info("任务执行完成"));
+        asyncTask.onError(() -> BaseResult.out(CodeEnum.FAIL, "error"));
+        asyncTask.onTimeout(() -> BaseResult.out(CodeEnum.FAIL, "timeout"));
+
+        return asyncTask;
+    }
+}

+ 1 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/job/IotOperationPlanJob.java

@@ -48,7 +48,7 @@ import static cn.iocoder.yudao.module.pms.framework.config.MultiThreadConfigurat
  * @date 2025/5/11 10:26
  * @description
  */
-@Component
+//@Component
 @Slf4j
 public class IotOperationPlanJob implements JobHandler {
 

+ 41 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/yanfan/sip/RecordCacheManager.java

@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.pms.service.yanfan.sip;
+
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.model.RecordList;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantLock;
+
+@Component
+public class RecordCacheManager {
+    private final ConcurrentHashMap<String, RecordList> recordMap = new ConcurrentHashMap<>();
+    private final ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
+
+    public  void put(String key,RecordList list){
+        recordMap.putIfAbsent(key, list);
+    }
+
+    public  RecordList get(String key){
+        RecordList ret = recordMap.get(key);
+        if (ret == null) {
+            ret = new RecordList();
+            recordMap.putIfAbsent(key, ret);
+        }
+        return ret;
+    }
+
+    public void remove(String key) {
+        recordMap.remove(key);
+        lockMap.remove(key);
+    }
+
+    public void addlock(String key){
+        lockMap.put(key,new ReentrantLock());
+    }
+
+    public ReentrantLock getlock(String key){
+        return lockMap.get(key);
+    }
+
+
+}

+ 30 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/yanfan/sip/record/IRecordService.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.pms.service.yanfan.sip.record;
+
+import cn.iocoder.yudao.module.pms.service.yanfan.play.model.Stream;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.model.RecordItem;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.model.RecordList;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.List;
+
+public interface IRecordService {
+    RecordList listDevRecord(String deviceId, String channelId, String startTime, String endTime);
+    List<RecordItem> listRecord(String channelId, String sn);
+
+    JSONObject listServerRecord(String recordApi, Integer pageNum, Integer pageSize);
+    JSONArray listServerRecordByDate(String recordApi, Integer year, Integer month, String app, String stream);
+    JSONObject listServerRecordByStream(String recordApi, Integer pageNum, Integer pageSize, String app);
+    JSONObject listServerRecordByApp(String recordApi, Integer pageNum, Integer pageSize);
+    JSONObject listServerRecordByFile(String recordApi, Integer pageNum, Integer pageSize, String app, String stream, String startTime, String endTime);
+    JSONObject listServerRecordByDevice(Integer pageNum, Integer pageSize, String deviceId, String channelId, String startTime, String endTime);
+    boolean startRecord(String stream);
+    boolean stopRecord(String stream);
+    boolean isRecording(String stream);
+    JSONObject getMp4RecordFile(String stream,String period);
+    Stream download(String deviceId, String channelId,
+                    String startTime, String endTime, int downloadSpeed);
+//    JSONObject upload(String recordApi, String file);
+    Stream playRecord(String deviceId, String channelId);
+    JSONObject addStreamProxy(String deviceId, String url, Integer count);
+}

+ 219 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/yanfan/sip/record/RecordServiceImpl.java

@@ -0,0 +1,219 @@
+package cn.iocoder.yudao.module.pms.service.yanfan.sip.record;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.redis.RedisCache;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.redis.RedisKeyBuilder;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.sip.device.vo.YfSipDeviceRespVO;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.sip.vo.VideoSessionInfo;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils.RecordApiUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils.SipUtil;
+import cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils.ZlmApiUtils;
+import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.media.YfMediaServerDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.sip.device.YfSipDeviceDO;
+import cn.iocoder.yudao.module.pms.service.yanfan.media.YfMediaServerService;
+import cn.iocoder.yudao.module.pms.service.yanfan.play.IPlayService;
+import cn.iocoder.yudao.module.pms.service.yanfan.play.model.Stream;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.ISipCmd;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.IZmlHookService;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.MessageInvoker;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.RecordCacheManager;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.device.YfSipDeviceService;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.model.RecordItem;
+import cn.iocoder.yudao.module.pms.service.yanfan.sip.model.RecordList;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+
+@Slf4j
+@Service
+public class RecordServiceImpl implements IRecordService {
+
+    @Autowired
+    private MessageInvoker messageInvoker;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private RecordCacheManager recordCacheManager;
+
+    @Autowired
+    private YfSipDeviceService sipDeviceService;
+
+    @Autowired
+    private YfMediaServerService mediaServerService;
+
+    @Autowired
+    private IZmlHookService zmlHookService;
+
+    @Autowired
+    private ZlmApiUtils zlmApiUtils;
+
+    @Autowired
+    private RecordApiUtils recordApiUtils;
+
+    @Autowired
+    private ISipCmd sipCmd;
+
+    @Autowired
+    private IPlayService playService;
+
+//    @Autowired
+//    private IOssDetailService ossDetailService;
+
+    @Override
+    public RecordList listDevRecord(String deviceId, String channelId, String start, String end) {
+        YfSipDeviceDO dev = sipDeviceService.selectSipDeviceBySipId(deviceId);
+        if (dev != null) {
+            String sn = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
+            String recordkey = channelId + ":" + sn;
+            recordCacheManager.addlock(recordkey);
+            messageInvoker.recordInfoQuery(dev, sn, channelId, SipUtil.timestampToDate(start), SipUtil.timestampToDate(end));
+            String catchkey = RedisKeyBuilder.buildSipRecordinfoCacheKey(recordkey);
+            return (RecordList) messageInvoker.getExecResult(catchkey, SipUtil.DEFAULT_EXEC_TIMEOUT);
+        }
+        return null;
+    }
+
+    @Override
+    public List<RecordItem> listRecord(String channelId, String sn) {
+        String recordkey = channelId + ":" + sn;
+        String catchkey = RedisKeyBuilder.buildSipRecordinfoCacheKey(recordkey);
+        List<RecordItem> items = redisCache.getCacheList(catchkey);
+        if (items.size() > 1) {
+            items.sort(Comparator.naturalOrder());
+        }
+        return items;
+    }
+
+    @Override
+    public JSONObject listServerRecord(String recordApi, Integer pageNum, Integer pageSize) {
+        return recordApiUtils.getRecordlist(recordApi, pageNum, pageSize, null).getJSONObject("data");
+    }
+
+    @Override
+    public JSONArray listServerRecordByDate(String recordApi, Integer year, Integer month, String app, String stream) {
+        return recordApiUtils.getRecordDatelist(recordApi, year, month, app, stream, null).getJSONArray("data");
+    }
+
+    @Override
+    public JSONObject listServerRecordByStream(String recordApi, Integer pageNum, Integer pageSize, String app) {
+        return recordApiUtils.getRecordStreamlist(recordApi, pageNum, pageSize, app, null).getJSONObject("data");
+    }
+
+    @Override
+    public JSONObject listServerRecordByApp(String recordApi, Integer pageNum, Integer pageSize) {
+        return recordApiUtils.getRecordApplist(recordApi, pageNum, pageSize, null).getJSONObject("data");
+    }
+
+    @Override
+    public JSONObject listServerRecordByFile(String recordApi, Integer pageNum, Integer pageSize, String app, String stream, String startTime, String endTime) {
+        return recordApiUtils.getRecordFilelist(recordApi, pageNum, pageSize, app, stream, startTime, endTime, null).getJSONObject("data");
+    }
+
+    @Override
+    public JSONObject listServerRecordByDevice(Integer pageNum, Integer pageSize, String deviceId, String channelId, String startTime, String endTime) {
+        String playrsid = String.format("%s_%s_%s", SipUtil.PREFIX_PLAYRECORD, deviceId, channelId);
+        YfMediaServerDO mediaServer = mediaServerService.selectMediaServerBydeviceSipId(deviceId);
+        String recordApi = "";
+        if (mediaServer != null && Objects.equals(mediaServer.getProtocol(), "http")) {
+            recordApi = "http://" + mediaServer.getIp() + ":" + mediaServer.getRecordPort();
+        } else if (mediaServer != null && Objects.equals(mediaServer.getProtocol(), "https")) {
+            recordApi = "https://" + mediaServer.getDomain() + ":" + mediaServer.getRecordPort();
+        }
+        JSONObject obj = recordApiUtils.getRecordFilelist(recordApi, pageNum, pageSize, "rtp",
+                playrsid, startTime, endTime, null);
+        if (obj != null) {
+            obj = obj.getJSONObject("data");
+            obj.put("recordApi", recordApi);
+            log.info("obj:{}", obj);
+        }
+        return obj;
+    }
+
+    @Override
+    public boolean startRecord(String stream) {
+//        SysUser user = getLoginUser().getUser();
+        //缓存zlm服务器配置
+        YfMediaServerDO media = mediaServerService.selectMediaServerBytenantId(1L);
+        if (media != null) {
+            return zlmApiUtils.startRecord(media, "1", "live", stream).getBoolean("result");
+        }
+        return false;
+    }
+
+    @Override
+    public boolean stopRecord(String stream) {
+//        SysUser user = getLoginUser().getUser();
+        YfMediaServerDO media = mediaServerService.selectMediaServerBytenantId(1L);
+        if (media != null) {
+            return zlmApiUtils.stopRecord(media, "1", "live", stream).getBoolean("result");
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isRecording(String stream) {
+//        SysUser user = getLoginUser().getUser();
+        YfMediaServerDO media = mediaServerService.selectMediaServerBytenantId(1L);
+        if (media != null) {
+            return zlmApiUtils.isRecording(media, "1", "live", stream).getBoolean("status");
+        }
+        return false;
+    }
+
+    @Override
+    public JSONObject getMp4RecordFile(String stream, String period) {
+//        SysUser user = getLoginUser().getUser();
+        YfMediaServerDO media = mediaServerService.selectMediaServerBytenantId(1L);
+        if (media != null) {
+            return zlmApiUtils.getMp4RecordFile(media, period, "live", stream).getJSONObject("data");
+        }
+        return null;
+    }
+
+    @Override
+    public Stream download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed) {
+        YfSipDeviceDO dev = sipDeviceService.selectSipDeviceBySipId(deviceId);
+        YfSipDeviceRespVO bean = BeanUtil.toBean(dev, YfSipDeviceRespVO.class);
+        VideoSessionInfo info = sipCmd.downloadStreamCmd(bean, channelId, startTime, endTime, downloadSpeed);
+        return zmlHookService.updateStream(info);
+    }
+
+//    @Override
+//    public JSONObject upload(String recordApi, String file) {
+//        JSONObject obj = recordApiUtils.uploadOss(recordApi, file, null).getJSONObject("data");
+//        if (obj != null) {
+//            JSONObject ossObj = obj.getJSONObject("data");
+//            if (ossObj != null) {
+//                OssDetail ossDetail = OssDetail.builder()
+//                        .fileName(ossObj.getString("fileName"))
+//                        .fileSuffix(ossObj.getString("fileSuffix"))
+//                        .url(ossObj.getString("url"))
+//                        .originalName(ossObj.getString("originalName"))
+//                        .service(ossObj.getString("service"))
+//                        .build();
+//                ossDetailService.insertOssDetail(ossDetail);
+//            }
+//        }
+//        return obj;
+//    }
+
+    @Override
+    public Stream playRecord(String deviceId, String channelId) {
+        return playService.play(deviceId, channelId, true);
+    }
+
+    @Override
+    public JSONObject addStreamProxy(String deviceId, String proxyUrl, Integer count) {
+        YfMediaServerDO mediaServer = mediaServerService.selectMediaServerBydeviceSipId(deviceId);
+        return zlmApiUtils.addStreamProxy(mediaServer, "live", deviceId, proxyUrl, count);
+    }
+}