Sfoglia il codice sorgente

[录制计划] 增加录制计划执行

648540858 11 mesi fa
parent
commit
8a06562a88

+ 50 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java

@@ -498,6 +498,7 @@ public interface CommonGBChannelMapper {
             "    wdc.stream_proxy_id,\n" +
             "    wdc.create_time,\n" +
             "    wdc.update_time,\n" +
+            "    wdc.record_plan_id,\n" +
             "    coalesce( wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" +
             "    coalesce( wdc.gb_name, wdc.name) as gb_name,\n" +
             "    coalesce( wdc.gb_manufacturer, wdc.manufacturer) as gb_manufacturer,\n" +
@@ -548,4 +549,53 @@ public interface CommonGBChannelMapper {
     List<CommonGBChannel> queryForRecordPlanForWebList(@Param("planId") Integer planId, @Param("query") String query,
                                                        @Param("channelType") Integer channelType, @Param("online") Boolean online,
                                                        @Param("hasLink") Boolean hasLink);
+
+    @Select("<script>" +
+            " select " +
+            "    wdc.id as gb_id,\n" +
+            "    wdc.device_db_id as gb_device_db_id,\n" +
+            "    wdc.stream_push_id,\n" +
+            "    wdc.stream_proxy_id,\n" +
+            "    wdc.create_time,\n" +
+            "    wdc.update_time,\n" +
+            "    wdc.record_plan_id,\n" +
+            "    coalesce( wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" +
+            "    coalesce( wdc.gb_name, wdc.name) as gb_name,\n" +
+            "    coalesce( wdc.gb_manufacturer, wdc.manufacturer) as gb_manufacturer,\n" +
+            "    coalesce( wdc.gb_model, wdc.model) as gb_model,\n" +
+            "    coalesce( wdc.gb_owner, wdc.owner) as gb_owner,\n" +
+            "    coalesce( wdc.gb_civil_code, wdc.civil_code) as gb_civil_code,\n" +
+            "    coalesce( wdc.gb_block, wdc.block) as gb_block,\n" +
+            "    coalesce( wdc.gb_address, wdc.address) as gb_address,\n" +
+            "    coalesce( wdc.gb_parental, wdc.parental) as gb_parental,\n" +
+            "    coalesce( wdc.gb_parent_id, wdc.parent_id) as gb_parent_id,\n" +
+            "    coalesce( wdc.gb_safety_way, wdc.safety_way) as gb_safety_way,\n" +
+            "    coalesce( wdc.gb_register_way, wdc.register_way) as gb_register_way,\n" +
+            "    coalesce( wdc.gb_cert_num, wdc.cert_num) as gb_cert_num,\n" +
+            "    coalesce( wdc.gb_certifiable, wdc.certifiable) as gb_certifiable,\n" +
+            "    coalesce( wdc.gb_err_code, wdc.err_code) as gb_err_code,\n" +
+            "    coalesce( wdc.gb_end_time, wdc.end_time) as gb_end_time,\n" +
+            "    coalesce( wdc.gb_secrecy, wdc.secrecy) as gb_secrecy,\n" +
+            "    coalesce( wdc.gb_ip_address, wdc.ip_address) as gb_ip_address,\n" +
+            "    coalesce( wdc.gb_port, wdc.port) as gb_port,\n" +
+            "    coalesce( wdc.gb_password, wdc.password) as gb_password,\n" +
+            "    coalesce( wdc.gb_status, wdc.status) as gb_status,\n" +
+            "    coalesce( wdc.gb_longitude, wdc.longitude) as gb_longitude,\n" +
+            "    coalesce( wdc.gb_latitude, wdc.latitude) as gb_latitude,\n" +
+            "    coalesce( wdc.gb_ptz_type, wdc.ptz_type) as gb_ptz_type,\n" +
+            "    coalesce( wdc.gb_position_type, wdc.position_type) as gb_position_type,\n" +
+            "    coalesce( wdc.gb_room_type, wdc.room_type) as gb_room_type,\n" +
+            "    coalesce( wdc.gb_use_type, wdc.use_type) as gb_use_type,\n" +
+            "    coalesce( wdc.gb_supply_light_type, wdc.supply_light_type) as gb_supply_light_type,\n" +
+            "    coalesce( wdc.gb_direction_type, wdc.direction_type) as gb_direction_type,\n" +
+            "    coalesce( wdc.gb_resolution, wdc.resolution) as gb_resolution,\n" +
+            "    coalesce( wdc.gb_business_group_id, wdc.business_group_id) as gb_business_group_id,\n" +
+            "    coalesce( wdc.gb_download_speed, wdc.download_speed) as gb_download_speed,\n" +
+            "    coalesce( wdc.gb_svc_space_support_mod, wdc.svc_space_support_mod) as gb_svc_space_support_mod,\n" +
+            "    coalesce( wdc.gb_svc_time_support_mode, wdc.svc_time_support_mode) as gb_svc_time_support_mode \n" +
+            " from wvp_device_channel wdc" +
+            " where wdc.record_plan_id in " +
+            " <foreach collection='planIdList'  item='item'  open='(' separator=',' close=')' > #{item}</foreach>" +
+            "</script>")
+    List<CommonGBChannel> queryForRecordPlan(List<Integer> planIdList);
 }

+ 4 - 48
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java

@@ -1,7 +1,11 @@
 package com.genersoft.iot.vmp.media.zlm.dto.hook;
 
 import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
+import lombok.Getter;
+import lombok.Setter;
 
+@Setter
+@Getter
 public class HookResultForOnPublish extends HookResult{
 
     private boolean enable_audio;
@@ -34,54 +38,6 @@ public class HookResultForOnPublish extends HookResult{
         setMsg(msg);
     }
 
-    public boolean isEnable_audio() {
-        return enable_audio;
-    }
-
-    public void setEnable_audio(boolean enable_audio) {
-        this.enable_audio = enable_audio;
-    }
-
-    public boolean isEnable_mp4() {
-        return enable_mp4;
-    }
-
-    public void setEnable_mp4(boolean enable_mp4) {
-        this.enable_mp4 = enable_mp4;
-    }
-
-    public int getMp4_max_second() {
-        return mp4_max_second;
-    }
-
-    public void setMp4_max_second(int mp4_max_second) {
-        this.mp4_max_second = mp4_max_second;
-    }
-
-    public String getMp4_save_path() {
-        return mp4_save_path;
-    }
-
-    public void setMp4_save_path(String mp4_save_path) {
-        this.mp4_save_path = mp4_save_path;
-    }
-
-    public String getStream_replace() {
-        return stream_replace;
-    }
-
-    public void setStream_replace(String stream_replace) {
-        this.stream_replace = stream_replace;
-    }
-
-    public Integer getModify_stamp() {
-        return modify_stamp;
-    }
-
-    public void setModify_stamp(Integer modify_stamp) {
-        this.modify_stamp = modify_stamp;
-    }
-
     @Override
     public String toString() {
         return "HookResultForOnPublish{" +

+ 2 - 1
src/main/java/com/genersoft/iot/vmp/service/IRecordPlanService.java

@@ -1,7 +1,6 @@
 package com.genersoft.iot.vmp.service;
 
 import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
-import com.genersoft.iot.vmp.gb28181.bean.PlatformChannel;
 import com.genersoft.iot.vmp.service.bean.RecordPlan;
 import com.github.pagehelper.PageInfo;
 
@@ -27,4 +26,6 @@ public interface IRecordPlanService {
     void linkAll(Integer planId);
 
     void cleanAll(Integer planId);
+
+    boolean recording(String app, String stream);
 }

+ 7 - 0
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java

@@ -15,6 +15,7 @@ import com.genersoft.iot.vmp.media.bean.MediaServer;
 import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
 import com.genersoft.iot.vmp.service.IMediaService;
+import com.genersoft.iot.vmp.service.IRecordPlanService;
 import com.genersoft.iot.vmp.service.IUserService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
@@ -59,6 +60,9 @@ public class MediaServiceImpl implements IMediaService {
     @Autowired
     private SipInviteSessionManager sessionManager;
 
+    @Autowired
+    private IRecordPlanService recordPlanService;
+
     @Override
     public boolean authenticatePlay(String app, String stream, String callId) {
         if (app == null || stream == null) {
@@ -205,6 +209,9 @@ public class MediaServiceImpl implements IMediaService {
     @Override
     public boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema) {
         boolean result = false;
+        if (recordPlanService.recording(app, stream)) {
+            return false;
+        }
         // 国标类型的流
         if ("rtp".equals(app)) {
             result = userSetting.getStreamOnDemand();

+ 81 - 17
src/main/java/com/genersoft/iot/vmp/service/impl/RecordPlanServiceImpl.java

@@ -1,12 +1,15 @@
 package com.genersoft.iot.vmp.service.impl;
 
+import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
 import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper;
-import com.genersoft.iot.vmp.gb28181.service.IGbChannelService;
-import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
+import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService;
+import com.genersoft.iot.vmp.media.bean.MediaInfo;
 import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
+import com.genersoft.iot.vmp.media.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IRecordPlanService;
+import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
 import com.genersoft.iot.vmp.service.bean.RecordPlan;
 import com.genersoft.iot.vmp.service.bean.RecordPlanItem;
 import com.genersoft.iot.vmp.storager.dao.RecordPlanMapper;
@@ -22,8 +25,8 @@ import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.time.LocalDateTime;
+import java.util.*;
 
 @Service
 @Slf4j
@@ -36,17 +39,12 @@ public class RecordPlanServiceImpl implements IRecordPlanService {
     private CommonGBChannelMapper channelMapper;
 
     @Autowired
-    private IGbChannelService channelService;
+    private IGbChannelPlayService channelPlayService;
 
+    @Autowired
+    private IMediaServerService mediaServerService;
 
-    /**
-     * 流到来的处理
-     */
-    @Async("taskExecutor")
-    @org.springframework.context.event.EventListener
-    public void onApplicationEvent(MediaArrivalEvent event) {
 
-    }
 
     /**
      * 流离开的处理
@@ -55,23 +53,89 @@ public class RecordPlanServiceImpl implements IRecordPlanService {
     @EventListener
     public void onApplicationEvent(MediaDepartureEvent event) {
         // 流断开,检查是否还处于录像状态, 如果是则继续录像
+        if (recording(event.getApp(), event.getStream())) {
+            // 重新拉起
 
+        }
     }
 
+    Map<Integer, StreamInfo> recordStreamMap = new HashMap<>();
+
     @Scheduled(cron = "0 */30 * * * *")
     public void execution() {
         // 执行计划
+
+        // 获取当前时间在一周内的序号
+        LocalDateTime now = LocalDateTime.now();
+        int week = now.getDayOfWeek().getValue();
+        int index = now.getHour() * 2 + (now.getMinute() > 30?1:0);
         // 查询startTime等于现在的, 开始录像
+        List<Integer> startPlanList = recordPlanMapper.queryStart(week, index);
+
+        Map<Integer, StreamInfo> channelMapWithoutRecord = new HashMap<>();
+        if (startPlanList.isEmpty()) {
+            // 停止所有正在录像的
+            if(recordStreamMap.isEmpty()) {
+                // 暂无录像任务
+                return;
+            }else {
+                channelMapWithoutRecord.putAll(recordStreamMap);
+                recordStreamMap.clear();
+            }
+        }else {
+            channelMapWithoutRecord.putAll(recordStreamMap);
+            // 获取所有的关联的通道
+            List<CommonGBChannel> channelList = channelMapper.queryForRecordPlan(startPlanList);
+            if (channelList.isEmpty()) {
+                recordStreamMap.clear();
+            }else {
+                // 查找是否已经开启录像, 如果没有则开启录像
+                for (CommonGBChannel channel : channelList) {
+                    if (recordStreamMap.get(channel.getGbId()) != null) {
+                        channelMapWithoutRecord.remove(channel.getGbId());
+                    }else {
+                        // 开启点播,
+                        channelPlayService.play(channel, null, ((code, msg, streamInfo) -> {
+                            if (code == InviteErrorCode.SUCCESS.getCode() && streamInfo != null) {
+                                log.info("[录像] 开启成功, 通道ID: {}", channel.getGbId());
+                                recordStreamMap.put(channel.getGbId(), streamInfo);
+                                channelMapWithoutRecord.remove(channel.getGbId(), streamInfo);
+                            }
+                        }));
+                    }
+                }
+            }
+        }
+        // 结束录像
+        if(!channelMapWithoutRecord.isEmpty()) {
+            for (Integer channelId : channelMapWithoutRecord.keySet()) {
+                StreamInfo streamInfo = channelMapWithoutRecord.get(channelId);
+                if (streamInfo == null) {
+                    continue;
+                }
+                // 查看是否有人观看,存在则不做处理,等待后续自然处理,如果无人观看,则关闭该流
+                MediaInfo mediaInfo = mediaServerService.getMediaInfo(streamInfo.getMediaServer(), streamInfo.getApp(), streamInfo.getStream());
+                if (mediaInfo.getReaderCount() == null ||  mediaInfo.getReaderCount() == 0) {
+                    mediaServerService.closeStreams(streamInfo.getMediaServer(), streamInfo.getApp(), streamInfo.getStream());
+                    log.info("[录像] 停止, 通道ID: {}", channelId);
+                }
+            }
+        }
+    }
 
-        // 查询stopTime等于现在的,结束录像
-        // 查询处于中间的,验证录像是否正在进行
+    // 系统启动时
 
 
-        // TODO 无人观看要确保处于录像状态的通道不被移除
+    @Override
+    public boolean recording(String app, String stream) {
+        for (StreamInfo streamInfo : recordStreamMap.values()) {
+            if (streamInfo.getApp().equals(app) && streamInfo.getStream().equals(stream)) {
+                return true;
+            }
+        }
+        return false;
     }
 
-    // 系统启动时
-
     @Override
     @Transactional
     public void add(RecordPlan plan) {

+ 3 - 0
src/main/java/com/genersoft/iot/vmp/storager/dao/RecordPlanMapper.java

@@ -58,4 +58,7 @@ public interface RecordPlanMapper {
 
     @Delete("DELETE FROM wvp_record_plan_item WHERE plan_id = #{planId}")
     void cleanItems(@Param("planId") Integer planId);
+
+    @Select("select plan_id from wvp_record_plan_item where  week_day = #{week} and start &gt;= #{index} and stop &lt;= #{index} group by plan_id")
+    List<Integer> queryStart(@Param("week") int week, @Param("index") int index);
 }

+ 0 - 2
web_src/src/components/dialog/editRecordPlan.vue

@@ -176,10 +176,8 @@ export default {
       let start = null;
       let stop = null;
       let result = []
-      console.log("===================")
       for (let i = 0; i < weekItem.length; i++) {
         let item = weekItem[i]
-        console.log(item)
         if (item === '1') { // 表示选中
           stop = i
           if (start === null ) {