Pu Zhibing
2025-03-24 87c2f1ec41e244dfdd4722884fcdf285a1fe9b41
完成音视频协议接口对接
2个文件已删除
9个文件已修改
12个文件已添加
1175 ■■■■ 已修改文件
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/controller/DOWNRealvideoMsgStartupController.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/controller/PlaybackMsgController.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/controller/RealVideoMsgController.java 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/dao/UPPlaybackMsgControlAckDao.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/dao/UPPlaybackMsgStartupAckDao.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/dao/UPRealvideoMsgEndAckDao.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/dao/UPRealvideoMsgStartupAckDao.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/DOWNPlaybackMsgControl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/DOWNPlaybackMsgStartup.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/DOWNRealvideoMsgEnd.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/PlaybackMsg.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/UPPlaybackMsgControlAck.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/UPPlaybackMsgStartupAck.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/UPRealvideoMsgEndAck.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/UPRealvideoMsgStartupAck.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/netty/server/NettyHandle.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/AuthorizeMsgService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/DOWNPlaybackMsgControlService.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/DOWNPlaybackMsgStartupService.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/DOWNRealvideoMsgEndService.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/PlaybackMsgService.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/RealvideoMsg.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/RealvideoMsgService.java 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/controller/DOWNRealvideoMsgStartupController.java
File was deleted
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/controller/PlaybackMsgController.java
New file
@@ -0,0 +1,112 @@
package com.ruoyi.dataInterchange.controller;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.dataInterchange.dao.UPPlaybackMsgControlAckDao;
import com.ruoyi.dataInterchange.dao.UPPlaybackMsgStartupAckDao;
import com.ruoyi.dataInterchange.model.UPPlaybackMsgControlAck;
import com.ruoyi.dataInterchange.model.UPPlaybackMsgStartupAck;
import com.ruoyi.dataInterchange.server.DOWNPlaybackMsgControlService;
import com.ruoyi.dataInterchange.server.DOWNPlaybackMsgStartupService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.time.LocalDateTime;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 9:45
 */
@RestController
@RequestMapping("/playbackMsg")
public class PlaybackMsgController {
    @Resource
    private DOWNPlaybackMsgStartupService downPlaybackMsgStartupService;
    @Resource
    private UPPlaybackMsgStartupAckDao upPlaybackMsgStartupAckDao;
    @Resource
    private UPPlaybackMsgControlAckDao upPlaybackMsgControlAckDao;
    @Resource
    private DOWNPlaybackMsgControlService downPlaybackMsgControlService;
    /**
     * 远程录像回放请求
     *
     * @param inferiorPlatformId
     * @param vehicleNo
     * @return
     */
    @PostMapping("/playbackMsgStartup")
    public R<UPPlaybackMsgStartupAck> playbackMsgStartup(@RequestParam("inferiorPlatformId") Integer inferiorPlatformId, @RequestParam("vehicleNo") String vehicleNo,
                                                         @RequestParam("startTime") LocalDateTime startTime, @RequestParam("endTime") LocalDateTime endTime) {
        R r = downPlaybackMsgStartupService.playbackMsgStartup(inferiorPlatformId, vehicleNo, startTime, endTime);
        if (200 != r.getCode()) {
            return r;
        }
        //发送成功,定时任务获取响应结果
        int num = 0;
        LocalDateTime now = LocalDateTime.now();
        while (true) {
            UPPlaybackMsgStartupAck upPlaybackMsgStartupAck = upPlaybackMsgStartupAckDao.findByInferiorPlatformIdAndVehicleNoAndCreateTimeAfter(inferiorPlatformId, vehicleNo, now);
            if (null == upPlaybackMsgStartupAck) {
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                num++;
                continue;
            }
            if (null != upPlaybackMsgStartupAck || num >= 30) {
                return R.ok(upPlaybackMsgStartupAck);
            }
        }
    }
    /**
     * 远程录像回放控制
     *
     * @param inferiorPlatformId 平台唯一码
     * @param vehicleNo          车牌号
     * @param controlType        控制类型
     * @param fastTime           快进快退倍数
     * @return
     */
    @PostMapping("/playbackMsgControl")
    public R<Integer> playbackMsgControl(@RequestParam("inferiorPlatformId") Integer inferiorPlatformId, @RequestParam("vehicleNo") String vehicleNo,
                                         @RequestParam("controlType") Integer controlType, @RequestParam("fastTime") Integer fastTime) {
        R r = downPlaybackMsgControlService.playbackMsgControl(inferiorPlatformId, vehicleNo, controlType, fastTime);
        if (200 != r.getCode()) {
            return r;
        }
        //发送成功,定时任务获取响应结果
        int num = 0;
        LocalDateTime now = LocalDateTime.now();
        while (true) {
            UPPlaybackMsgControlAck upPlaybackMsgControlAck = upPlaybackMsgControlAckDao.findByInferiorPlatformIdAndVehicleNoAndCreateTimeAfter(inferiorPlatformId, vehicleNo, now);
            if (null == upPlaybackMsgControlAck) {
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                num++;
                continue;
            }
            if (null != upPlaybackMsgControlAck) {
                return R.ok(upPlaybackMsgControlAck.getResult());
            }
            if (num >= 30) {
                return R.fail("远程响应失败");
            }
        }
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/controller/RealVideoMsgController.java
New file
@@ -0,0 +1,108 @@
package com.ruoyi.dataInterchange.controller;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.dataInterchange.dao.UPRealvideoMsgEndAckDao;
import com.ruoyi.dataInterchange.dao.UPRealvideoMsgStartupAckDao;
import com.ruoyi.dataInterchange.model.UPRealvideoMsgEndAck;
import com.ruoyi.dataInterchange.model.UPRealvideoMsgStartupAck;
import com.ruoyi.dataInterchange.server.DOWNRealvideoMsgEndService;
import com.ruoyi.dataInterchange.server.DOWNRealvideoMsgStartupService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.time.LocalDateTime;
/**
 * 实时音视频控制器
 *
 * @author zhibing.pu
 * @Date 2025/3/21 11:11
 */
@RestController
@RequestMapping("/realVideoMsg")
public class RealVideoMsgController {
    @Resource
    private DOWNRealvideoMsgStartupService downRealvideoMsgStartupService;
    @Resource
    private UPRealvideoMsgStartupAckDao upRealvideoMsgStartupAckDao;
    @Resource
    private DOWNRealvideoMsgEndService downRealvideoMsgEndService;
    @Resource
    private UPRealvideoMsgEndAckDao upRealvideoMsgEndAckDao;
    /**
     * 发起实时音视频请求
     *
     * @param vehicleNo 车牌号
     * @return
     */
    @PostMapping("/startupRealVideo")
    public R<UPRealvideoMsgStartupAck> startupRealVideo(@RequestParam("inferiorPlatformId") Integer inferiorPlatformId, @RequestParam("vehicleNo") String vehicleNo) {
        R realVideo = downRealvideoMsgStartupService.startupRealVideo(inferiorPlatformId, vehicleNo);
        if (realVideo.getCode() != 200) {
            return realVideo;
        }
        //发送成功,定时任务获取响应结果
        int num = 0;
        LocalDateTime now = LocalDateTime.now();
        while (true) {
            UPRealvideoMsgStartupAck realvideoMsgStartupAck = upRealvideoMsgStartupAckDao.findByInferiorPlatformIdAndVehicleNoAndCreateTimeAfter(inferiorPlatformId, vehicleNo, now);
            if (null == realvideoMsgStartupAck) {
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                num++;
                continue;
            }
            if (null != realvideoMsgStartupAck || num >= 30) {
                return R.ok(realvideoMsgStartupAck);
            }
        }
    }
    /**
     * 主动请求停止实时音视频
     *
     * @param vehicleNo 车牌号
     * @return
     */
    @PostMapping("/stopRealVideo")
    public R<?> stopRealVideo(@RequestParam("inferiorPlatformId") Integer inferiorPlatformId, @RequestParam("vehicleNo") String vehicleNo) {
        R r = downRealvideoMsgEndService.stopRealVideo(inferiorPlatformId, vehicleNo);
        if (r.getCode() != 200) {
            return r;
        }
        //发送成功,定时任务获取响应结果
        int num = 0;
        LocalDateTime now = LocalDateTime.now();
        while (true) {
            UPRealvideoMsgEndAck upRealvideoMsgEndAck = upRealvideoMsgEndAckDao.findByInferiorPlatformIdAndVehicleNoAndCreateTimeAfter(inferiorPlatformId, vehicleNo, now);
            if (null == upRealvideoMsgEndAck) {
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                num++;
                continue;
            }
            if (null != upRealvideoMsgEndAck) {
                return R.ok(upRealvideoMsgEndAck.getResult());
            }
            if (num >= 30) {
                return R.fail("远程响应失败");
            }
        }
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/dao/UPPlaybackMsgControlAckDao.java
New file
@@ -0,0 +1,27 @@
package com.ruoyi.dataInterchange.dao;
import com.ruoyi.dataInterchange.model.UPPlaybackMsgControlAck;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 10:13
 */
@Repository
public interface UPPlaybackMsgControlAckDao extends ElasticsearchRepository<UPPlaybackMsgControlAck, String> {
    /**
     * 获取远程录像回放控制应答
     *
     * @param inferiorPlatformId
     * @param vehicleNo
     * @param createTime
     * @return
     */
    UPPlaybackMsgControlAck findByInferiorPlatformIdAndVehicleNoAndCreateTimeAfter(Integer inferiorPlatformId,
                                                                                   String vehicleNo, LocalDateTime createTime);
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/dao/UPPlaybackMsgStartupAckDao.java
New file
@@ -0,0 +1,26 @@
package com.ruoyi.dataInterchange.dao;
import com.ruoyi.dataInterchange.model.UPPlaybackMsgStartupAck;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 10:10
 */
@Repository
public interface UPPlaybackMsgStartupAckDao extends ElasticsearchRepository<UPPlaybackMsgStartupAck, String> {
    /**
     * 获取最新的远程录像请求回复消息
     *
     * @param inferiorPlatformId
     * @param vehicleNo
     * @param createTime
     * @return
     */
    UPPlaybackMsgStartupAck findByInferiorPlatformIdAndVehicleNoAndCreateTimeAfter(Integer inferiorPlatformId,
                                                                                   String vehicleNo, LocalDateTime createTime);
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/dao/UPRealvideoMsgEndAckDao.java
New file
@@ -0,0 +1,24 @@
package com.ruoyi.dataInterchange.dao;
import com.ruoyi.dataInterchange.model.UPRealvideoMsgEndAck;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 9:39
 */
@Repository
public interface UPRealvideoMsgEndAckDao extends ElasticsearchRepository<UPRealvideoMsgEndAck, String> {
    /**
     * 根据平台唯一id获取数据
     *
     * @param inferiorPlatformId
     * @return
     */
    UPRealvideoMsgEndAck findByInferiorPlatformIdAndVehicleNoAndCreateTimeAfter(Integer inferiorPlatformId,
                                                                                String vehicleNo, LocalDateTime createTime);
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/dao/UPRealvideoMsgStartupAckDao.java
New file
@@ -0,0 +1,27 @@
package com.ruoyi.dataInterchange.dao;
import com.ruoyi.dataInterchange.model.UPRealvideoMsgStartupAck;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 9:16
 */
@Repository
public interface UPRealvideoMsgStartupAckDao extends ElasticsearchRepository<UPRealvideoMsgStartupAck, String> {
    /**
     * 根据平台唯一id获取数据
     *
     * @param inferiorPlatformId
     * @return
     */
    UPRealvideoMsgStartupAck findByInferiorPlatformIdAndVehicleNoAndCreateTimeAfter(Integer inferiorPlatformId,
                                                                                    String vehicleNo, LocalDateTime createTime);
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/DOWNPlaybackMsgControl.java
@@ -1,5 +1,8 @@
package com.ruoyi.dataInterchange.model;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import lombok.Data;
/**
@@ -52,4 +55,33 @@
     */
    private Long dateTime;
    
    /**
     * 编码回复报文
     */
    public byte[] encode() {
        ByteBuf byteBuf = Unpooled.buffer(38);
        byte[] bytes1 = this.getVehicleNo().getBytes();
        for (int i = 0; i < 21; i++) {
            if (i < bytes1.length) {
                byteBuf.writeByte(bytes1[i]);
            } else {
                byteBuf.writeByte(0x00);
            }
        }
        byteBuf.writeByte(this.getVehicleColor());
        byteBuf.writeShort(this.getDataType());
        byteBuf.writeInt(this.getDataLength());
        byteBuf.writeChar(this.getControlType());
        byteBuf.writeChar(this.getFastTime());
        if (null != this.getDateTime()) {
            byteBuf.writeLong(this.getDateTime());
        } else {
            byteBuf.writeLong(0x00);
        }
        byte[] bytes = ByteBufUtil.getBytes(byteBuf);
        byteBuf.release();
        return bytes;
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/DOWNPlaybackMsgStartup.java
@@ -1,5 +1,8 @@
package com.ruoyi.dataInterchange.model;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import lombok.Data;
/**
@@ -67,4 +70,48 @@
     * 车辆进入跨域地区后5min之内的任一位置
     */
    private String gnssData;
    /**
     * 编码回复报文
     */
    public byte[] encode() {
        ByteBuf byteBuf = Unpooled.buffer(148);
        byte[] bytes1 = this.getVehicleNo().getBytes();
        for (int i = 0; i < 21; i++) {
            if (i < bytes1.length) {
                byteBuf.writeByte(bytes1[i]);
            } else {
                byteBuf.writeByte(0x00);
            }
        }
        byteBuf.writeByte(this.getVehicleColor());
        byteBuf.writeShort(this.getDataType());
        byteBuf.writeInt(this.getDataLength());
        byteBuf.writeChar(this.getChannelId());
        byteBuf.writeChar(this.getAvttemType());
        byteBuf.writeChar(this.getStreamType());
        byteBuf.writeChar(this.getMemType());
        byteBuf.writeLong(this.getPlaybackStartTime());
        byteBuf.writeLong(this.getPlaybackEndTime());
        byte[] bytes2 = this.getAuthorizeCode().getBytes();
        for (int i = 0; i < 64; i++) {
            if (i < bytes2.length) {
                byteBuf.writeByte(bytes2[i]);
            } else {
                byteBuf.writeByte(0x00);
            }
        }
        byte[] bytes3 = this.getGnssData().getBytes();
        for (int i = 0; i < 36; i++) {
            if (i < bytes3.length) {
                byteBuf.writeByte(bytes3[i]);
            } else {
                byteBuf.writeByte(0x00);
            }
        }
        byte[] bytes = ByteBufUtil.getBytes(byteBuf);
        byteBuf.release();
        return bytes;
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/DOWNRealvideoMsgEnd.java
@@ -1,5 +1,8 @@
package com.ruoyi.dataInterchange.model;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import lombok.Data;
/**
@@ -37,4 +40,28 @@
     * 0x02: 视频
     */
    private Integer avttemType;
    /**
     * 编码回复报文
     */
    public byte[] encode() {
        ByteBuf byteBuf = Unpooled.buffer(30);
        byte[] bytes1 = this.getVehicleNo().getBytes();
        for (int i = 0; i < 21; i++) {
            if (i < bytes1.length) {
                byteBuf.writeByte(bytes1[i]);
            } else {
                byteBuf.writeByte(0x00);
            }
        }
        byteBuf.writeByte(this.getVehicleColor());
        byteBuf.writeShort(this.getDataType());
        byteBuf.writeInt(this.getDataLength());
        byteBuf.writeChar(this.getChannelId());
        byteBuf.writeChar(this.getAvttemType());
        byte[] bytes = ByteBufUtil.getBytes(byteBuf);
        byteBuf.release();
        return bytes;
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/PlaybackMsg.java
New file
@@ -0,0 +1,31 @@
package com.ruoyi.dataInterchange.model;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 9:44
 */
@Data
public class PlaybackMsg {
    /**
     * 车牌号
     */
    private String vehicleNo;
    /**
     * 车牌颜色
     */
    private int vehicleColor;
    /**
     * 子业务类型标识
     */
    private int dataType;
    /**
     * 后续数据长度
     */
    private int dataLength;
    /**
     * 数据部分
     */
    private byte[] data;
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/UPPlaybackMsgControlAck.java
@@ -1,6 +1,12 @@
package com.ruoyi.dataInterchange.model;
import com.ruoyi.dataInterchange.pojo.BaseModel;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
 * 远程录像回放控制请求应答
@@ -9,22 +15,27 @@
 * @Date 2025/3/21 10:37
 */
@Data
public class UPPlaybackMsgControlAck {
@Document(indexName = "up_playback_msg_control_ack")
public class UPPlaybackMsgControlAck extends BaseModel {
    /**
     * 车牌号
     */
    @Field(type = FieldType.Text)
    private String vehicleNo;
    /**
     * 车牌颜色
     */
    @Field(type = FieldType.Integer)
    private Integer vehicleColor;
    /**
     * 子业务类型标识
     */
    @Field(type = FieldType.Integer)
    private Integer dataType;
    /**
     * 后续数据长度
     */
    @Field(type = FieldType.Integer)
    private Integer dataLength;
    /**
     * 应答结果
@@ -33,5 +44,21 @@
     * 0x02: 不支持
     * 0x03: 会话结束
     */
    private Integer result;
    @Field(type = FieldType.Integer)
    private int result;
    /**
     * 解析报文
     */
    public UPPlaybackMsgControlAck decode(PlaybackMsg playbackMsg) {
        byte[] data = playbackMsg.getData();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(data);
        this.vehicleNo = playbackMsg.getVehicleNo();
        this.vehicleColor = playbackMsg.getVehicleColor();
        this.dataType = playbackMsg.getDataType();
        this.dataLength = playbackMsg.getDataLength();
        this.result = byteBuf.readByte();
        return this;
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/UPPlaybackMsgStartupAck.java
@@ -1,6 +1,13 @@
package com.ruoyi.dataInterchange.model;
import com.ruoyi.dataInterchange.pojo.BaseModel;
import com.ruoyi.dataInterchange.util.jtt809.common.Jtt809Util;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
 * 远程录像回放请求应答
@@ -9,31 +16,38 @@
 * @Date 2025/3/21 10:04
 */
@Data
public class UPPlaybackMsgStartupAck {
@Document(indexName = "up_playback_msg_startup_ack")
public class UPPlaybackMsgStartupAck extends BaseModel {
    /**
     * 车牌号
     */
    @Field(type = FieldType.Text)
    private String vehicleNo;
    /**
     * 车牌颜色
     */
    @Field(type = FieldType.Integer)
    private Integer vehicleColor;
    /**
     * 子业务类型标识
     */
    @Field(type = FieldType.Integer)
    private Integer dataType;
    /**
     * 后续数据长度
     */
    @Field(type = FieldType.Integer)
    private Integer dataLength;
    /**
     * 企业视频服务器IP地址
     */
    @Field(type = FieldType.Text)
    private String serverIP;
    /**
     * 企业视频服务端口号
     */
    private Integer serverPort;
    @Field(type = FieldType.Integer)
    private int serverPort;
    /**
     * 应答结果
     * 0x00: 成功
@@ -43,5 +57,24 @@
     * 0x04: 失效口令错误
     * 0x05: 不满足跨域条件
     */
    private Integer result;
    @Field(type = FieldType.Integer)
    private int result;
    /**
     * 解析报文
     */
    public UPPlaybackMsgStartupAck decode(PlaybackMsg playbackMsg) {
        byte[] data = playbackMsg.getData();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(data);
        this.vehicleNo = playbackMsg.getVehicleNo();
        this.vehicleColor = playbackMsg.getVehicleColor();
        this.dataType = playbackMsg.getDataType();
        this.dataLength = playbackMsg.getDataLength();
        this.serverIP = Jtt809Util.readGBKString(byteBuf, 32);
        this.serverPort = byteBuf.readShort();
        this.result = byteBuf.readByte();
        return this;
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/UPRealvideoMsgEndAck.java
@@ -1,6 +1,11 @@
package com.ruoyi.dataInterchange.model;
import com.ruoyi.dataInterchange.pojo.BaseModel;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
 * 主动请求停止实时音视频传输应答
@@ -9,22 +14,26 @@
 * @Date 2025/3/21 9:54
 */
@Data
public class UPRealvideoMsgEndAck {
public class UPRealvideoMsgEndAck extends BaseModel {
    /**
     * 车牌号
     */
    @Field(type = FieldType.Text)
    private String vehicleNo;
    /**
     * 车牌颜色
     */
    @Field(type = FieldType.Integer)
    private Integer vehicleColor;
    /**
     * 子业务类型标识
     */
    @Field(type = FieldType.Integer)
    private Integer dataType;
    /**
     * 后续数据长度
     */
    @Field(type = FieldType.Integer)
    private Integer dataLength;
    /**
     * 应答结果
@@ -33,5 +42,23 @@
     * 0x02: 不支持
     * 0x03: 会话结束
     */
    private Integer result;
    @Field(type = FieldType.Integer)
    private int result;
    /**
     * 解析报文
     */
    public UPRealvideoMsgEndAck decode(RealVideoMsg realVideoMsg) {
        byte[] data = realVideoMsg.getData();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(data);
        this.vehicleNo = realVideoMsg.getVehicleNo();
        this.vehicleColor = realVideoMsg.getVehicleColor();
        this.dataType = realVideoMsg.getDataType();
        this.dataLength = realVideoMsg.getDataLength();
        //报警处理结果
        this.result = byteBuf.readByte();
        return this;
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/model/UPRealvideoMsgStartupAck.java
@@ -1,6 +1,13 @@
package com.ruoyi.dataInterchange.model;
import com.ruoyi.dataInterchange.pojo.BaseModel;
import com.ruoyi.dataInterchange.util.jtt809.common.Jtt809Util;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
 * 实时音视频请求应答
@@ -9,22 +16,27 @@
 * @Date 2025/3/21 9:45
 */
@Data
public class UPRealvideoMsgStartupAck {
@Document(indexName = "up_realvideo_msg_startup_ack")
public class UPRealvideoMsgStartupAck extends BaseModel {
    /**
     * 车牌号
     */
    @Field(type = FieldType.Text)
    private String vehicleNo;
    /**
     * 车牌颜色
     */
    @Field(type = FieldType.Integer)
    private Integer vehicleColor;
    /**
     * 子业务类型标识
     */
    @Field(type = FieldType.Integer)
    private Integer dataType;
    /**
     * 后续数据长度
     */
    @Field(type = FieldType.Integer)
    private Integer dataLength;
    /**
     * 应答结果
@@ -35,13 +47,34 @@
     * 0x04: 失效口令错误
     * 0x05: 不满足跨域条件
     */
    private Integer result;
    @Field(type = FieldType.Integer)
    private int result;
    /**
     * 企业视频服务器IP地址
     */
    @Field(type = FieldType.Text)
    private String serverIP;
    /**
     * 企业视频服务端口号
     */
    private Integer serverPort;
    @Field(type = FieldType.Integer)
    private int serverPort;
    /**
     * 解析报文
     */
    public UPRealvideoMsgStartupAck decode(RealVideoMsg realVideoMsg) {
        byte[] data = realVideoMsg.getData();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(data);
        this.vehicleNo = realVideoMsg.getVehicleNo();
        this.vehicleColor = realVideoMsg.getVehicleColor();
        this.dataType = realVideoMsg.getDataType();
        this.dataLength = realVideoMsg.getDataLength();
        //报警处理结果
        this.result = byteBuf.readByte();
        this.serverIP = Jtt809Util.readGBKString(byteBuf, 32);
        this.serverPort = byteBuf.readShort();
        return this;
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/netty/server/NettyHandle.java
@@ -58,7 +58,10 @@
    private AuthorizeMsgService authorizeMsgService = SpringUtils.getBean(AuthorizeMsgService.class);
    
    @Resource
    private RealvideoMsg realvideoMsg = SpringUtils.getBean(RealvideoMsg.class);
    private RealvideoMsgService realvideoMsgService = SpringUtils.getBean(RealvideoMsgService.class);
    @Resource
    private PlaybackMsgService playbackMsgService = SpringUtils.getBean(PlaybackMsgService.class);
    
    
    @Override
@@ -160,12 +163,16 @@
                baseMsgService.up_base_msg(ctx, out);
                break;
            case UP_AUTHORIZE_MSG:
                log.info("主链路视频时效口令交互({}):{}", DataType.UP_AUTHORIZE_MSG.getCode(), out);
                log.info("视频时效口令交互({}):{}", DataType.UP_AUTHORIZE_MSG.getCode(), out);
                authorizeMsgService.up_authorize_msg(ctx, out);
                break;
            case UP_REALVIDEO_MSG:
                log.info("主链路实时音视频交互({}):{}", DataType.UP_REALVIDEO_MSG.getCode(), out);
                realvideoMsg.up_realvideo_msg(ctx, out);
                log.info("实时音视频交互({}):{}", DataType.UP_REALVIDEO_MSG.getCode(), out);
                realvideoMsgService.up_realvideo_msg(ctx, out);
                break;
            case UP_PLAYBACK_MSG:
                log.info("远程录像回放交互({}):{}", DataType.UP_PLAYBACK_MSG.getCode(), out);
                playbackMsgService.up_playback_msg(ctx, out);
                break;
            default:
                break;
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/AuthorizeMsgService.java
@@ -40,7 +40,7 @@
        byte[] body = out.getBody();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(body);
        UPAuthorizeMsgStartup startup = new UPAuthorizeMsgStartup().decode(byteBuf);
        log.info("主链路视频时效口令上报:" + JSON.toJSONString(startup));
        log.info("视频时效口令上报:" + JSON.toJSONString(startup));
        startup.setInferiorPlatformId(out.getGnsscenterId());
        startup.setCreateTime(LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)));
        upAuthorizeMsgStartupDao.save(startup);
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/DOWNPlaybackMsgControlService.java
New file
@@ -0,0 +1,59 @@
package com.ruoyi.dataInterchange.server;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.dataInterchange.dao.UPExgMsgRegisterDao;
import com.ruoyi.dataInterchange.model.DOWNPlaybackMsgControl;
import com.ruoyi.dataInterchange.model.UPExgMsgRegister;
import com.ruoyi.dataInterchange.model.enu.DataType;
import com.ruoyi.dataInterchange.netty.client.ChannelMap;
import com.ruoyi.dataInterchange.util.jtt809.packet.common.OuterPacket;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 11:51
 */
@Slf4j
@Service
public class DOWNPlaybackMsgControlService {
    @Resource
    private UPExgMsgRegisterDao upExgMsgRegisterDao;
    /**
     * 远程录像回放控制
     *
     * @param inferiorPlatformId
     * @param vehicleNo
     * @param controlType
     * @param fastTime
     * @return
     */
    public R playbackMsgControl(Integer inferiorPlatformId, String vehicleNo, Integer controlType, Integer fastTime) {
        Channel channel = ChannelMap.getClientChannel(inferiorPlatformId);
        if (!channel.isActive()) {
            return R.fail("失败");
        }
        //查询车辆信息
        UPExgMsgRegister exgMsgRegister = upExgMsgRegisterDao.findByVehicleNo(vehicleNo);
        DOWNPlaybackMsgControl downPlaybackMsgControl = new DOWNPlaybackMsgControl();
        downPlaybackMsgControl.setVehicleNo(exgMsgRegister.getVehicleNo());
        downPlaybackMsgControl.setVehicleColor(exgMsgRegister.getVehicleColor());
        downPlaybackMsgControl.setDataType(DataType.DOWN_PLAYBACK_MSG_CONTROL.getCode());
        downPlaybackMsgControl.setDataLength(10);
        downPlaybackMsgControl.setControlType(controlType);
        downPlaybackMsgControl.setFastTime(fastTime);
        downPlaybackMsgControl.setDateTime(null);
        byte[] body = downPlaybackMsgControl.encode();
        OuterPacket out = new OuterPacket(DataType.DOWN_PLAYBACK_MSG.getCode(), body);
        channel.writeAndFlush(out);
        log.info("远程录像回放控制请求({}):{}", DataType.DOWN_PLAYBACK_MSG_CONTROL.getCode(), JSON.toJSONString(downPlaybackMsgControl));
        return R.ok();
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/DOWNPlaybackMsgStartupService.java
New file
@@ -0,0 +1,73 @@
package com.ruoyi.dataInterchange.server;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.dataInterchange.dao.UPAuthorizeMsgStartupDao;
import com.ruoyi.dataInterchange.dao.UPExgMsgRegisterDao;
import com.ruoyi.dataInterchange.model.DOWNPlaybackMsgStartup;
import com.ruoyi.dataInterchange.model.UPAuthorizeMsgStartup;
import com.ruoyi.dataInterchange.model.UPExgMsgRegister;
import com.ruoyi.dataInterchange.model.enu.DataType;
import com.ruoyi.dataInterchange.netty.client.ChannelMap;
import com.ruoyi.dataInterchange.util.jtt809.packet.common.OuterPacket;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 10:17
 */
@Slf4j
@Service
public class DOWNPlaybackMsgStartupService {
    @Resource
    private UPExgMsgRegisterDao upExgMsgRegisterDao;
    @Resource
    private UPAuthorizeMsgStartupDao upAuthorizeMsgStartupDao;
    /**
     * 远程录像回放请求
     *
     * @param inferiorPlatformId
     * @param vehicleNo
     * @return
     */
    public R playbackMsgStartup(Integer inferiorPlatformId, String vehicleNo, LocalDateTime startTime, LocalDateTime endTime) {
        Channel channel = ChannelMap.getClientChannel(inferiorPlatformId);
        if (!channel.isActive()) {
            return R.fail("失败");
        }
        //查询车辆信息
        UPExgMsgRegister exgMsgRegister = upExgMsgRegisterDao.findByVehicleNo(vehicleNo);
        UPAuthorizeMsgStartup authorizeMsgStartup = upAuthorizeMsgStartupDao.findByInferiorPlatformIdOrderByCreateTimeDesc(inferiorPlatformId);
        if (null == authorizeMsgStartup) {
            return R.fail("获取失效口令失败");
        }
        DOWNPlaybackMsgStartup downPlaybackMsgStartup = new DOWNPlaybackMsgStartup();
        downPlaybackMsgStartup.setVehicleNo(exgMsgRegister.getVehicleNo());
        downPlaybackMsgStartup.setVehicleColor(exgMsgRegister.getVehicleColor());
        downPlaybackMsgStartup.setDataType(DataType.DOWN_PLAYBACK_MSG_STARTUP.getCode());
        downPlaybackMsgStartup.setDataLength(2);
        downPlaybackMsgStartup.setChannelId(1);
        downPlaybackMsgStartup.setAvttemType(0X00);
        downPlaybackMsgStartup.setStreamType(0);
        downPlaybackMsgStartup.setMemType(0);
        downPlaybackMsgStartup.setPlaybackStartTime(startTime.toEpochSecond(ZoneOffset.ofHours(8)));
        downPlaybackMsgStartup.setPlaybackEndTime(endTime.toEpochSecond(ZoneOffset.ofHours(8)));
        downPlaybackMsgStartup.setAuthorizeCode(authorizeMsgStartup.getAuthorizeCode1());
        downPlaybackMsgStartup.setGnssData("");
        byte[] body = downPlaybackMsgStartup.encode();
        OuterPacket out = new OuterPacket(DataType.DOWN_PLAYBACK_MSG.getCode(), body);
        channel.writeAndFlush(out);
        log.info("远程录像回放请求({}):{}", DataType.DOWN_PLAYBACK_MSG_STARTUP.getCode(), JSON.toJSONString(downPlaybackMsgStartup));
        return R.ok();
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/DOWNRealvideoMsgEndService.java
New file
@@ -0,0 +1,55 @@
package com.ruoyi.dataInterchange.server;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.dataInterchange.dao.UPExgMsgRegisterDao;
import com.ruoyi.dataInterchange.model.DOWNRealvideoMsgEnd;
import com.ruoyi.dataInterchange.model.UPExgMsgRegister;
import com.ruoyi.dataInterchange.model.enu.DataType;
import com.ruoyi.dataInterchange.netty.client.ChannelMap;
import com.ruoyi.dataInterchange.util.jtt809.packet.common.OuterPacket;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 9:24
 */
@Slf4j
@Service
public class DOWNRealvideoMsgEndService {
    @Resource
    private UPExgMsgRegisterDao upExgMsgRegisterDao;
    /**
     * 发起实时音视频请求
     *
     * @param vehicleNo
     */
    public R stopRealVideo(Integer inferiorPlatformId, String vehicleNo) {
        Channel channel = ChannelMap.getClientChannel(inferiorPlatformId);
        if (!channel.isActive()) {
            return R.fail("失败");
        }
        //查询车辆信息
        UPExgMsgRegister exgMsgRegister = upExgMsgRegisterDao.findByVehicleNo(vehicleNo);
        DOWNRealvideoMsgEnd downRealvideoMsgEnd = new DOWNRealvideoMsgEnd();
        downRealvideoMsgEnd.setVehicleNo(exgMsgRegister.getVehicleNo());
        downRealvideoMsgEnd.setVehicleColor(exgMsgRegister.getVehicleColor());
        downRealvideoMsgEnd.setDataType(DataType.DOWN_REALVIDEO_MSG_END.getCode());
        downRealvideoMsgEnd.setDataLength(2);
        downRealvideoMsgEnd.setChannelId(1);
        downRealvideoMsgEnd.setAvttemType(0X00);
        byte[] body = downRealvideoMsgEnd.encode();
        OuterPacket out = new OuterPacket(DataType.DOWN_REALVIDEO_MSG.getCode(), body);
        channel.writeAndFlush(out);
        log.info("主动请求停止实时音视频({}):{}", DataType.DOWN_REALVIDEO_MSG_END.getCode(), JSON.toJSONString(downRealvideoMsgEnd));
        return R.ok();
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/PlaybackMsgService.java
New file
@@ -0,0 +1,120 @@
package com.ruoyi.dataInterchange.server;
import com.ruoyi.dataInterchange.dao.UPPlaybackMsgControlAckDao;
import com.ruoyi.dataInterchange.dao.UPPlaybackMsgStartupAckDao;
import com.ruoyi.dataInterchange.model.PlaybackMsg;
import com.ruoyi.dataInterchange.model.UPPlaybackMsgControlAck;
import com.ruoyi.dataInterchange.model.UPPlaybackMsgStartupAck;
import com.ruoyi.dataInterchange.model.enu.DataType;
import com.ruoyi.dataInterchange.util.jtt809.common.Jtt809Util;
import com.ruoyi.dataInterchange.util.jtt809.packet.common.OuterPacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
/**
 * @author zhibing.pu
 * @Date 2025/3/24 9:54
 */
@Slf4j
@Service
public class PlaybackMsgService {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private UPPlaybackMsgStartupAckDao upPlaybackMsgStartupAckDao;
    @Resource
    private UPPlaybackMsgControlAckDao upPlaybackMsgControlAckDao;
    /**
     * 从链路远程录像回放交互
     *
     * @param ctx
     * @param out
     */
    public void up_playback_msg(ChannelHandlerContext ctx, OuterPacket out) {
        if (!redisTemplate.hasKey("login:" + out.getGnsscenterId())) {
            log.error("链路还未登录校验,拒绝连接");
            ctx.close();
            return;
        }
        PlaybackMsg realVideoMsg = getPlaybackMsg(out);
        DataType dataType = DataType.getDataType(realVideoMsg.getDataType());
        switch (dataType) {
            case UP_PLAYBACK_MSG_STARTUP_ACK:
                log.info("远程录像回放请求应答({}):{}", DataType.UP_PLAYBACK_MSG_STARTUP_ACK.getCode(), out);
                up_playback_msg_startup_ack(ctx, out.getGnsscenterId(), realVideoMsg);
                break;
            case UP_PLAYBACK_MSG_CONTROL_ACK:
                log.info("远程录像回放控制请求应答({}):{}", DataType.UP_PLAYBACK_MSG_CONTROL_ACK.getCode(), out);
                up_playback_msg_control_ack(ctx, out.getGnsscenterId(), realVideoMsg);
                break;
            default:
                break;
        }
    }
    public PlaybackMsg getPlaybackMsg(OuterPacket out) {
        byte[] body = out.getBody();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(body);
        //车牌号
        String vehicleNo = Jtt809Util.readGBKString(byteBuf, 21);
        //车牌颜色
        byte vehicleColor = byteBuf.readByte();
        //子业务类型标识
        int dataType = byteBuf.readUnsignedShort();
        //后续数据长度
        int dataLength = byteBuf.readInt();
        //子业务数据包
        byte[] data = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(data);
        PlaybackMsg playbackMsg = new PlaybackMsg();
        playbackMsg.setVehicleNo(vehicleNo);
        playbackMsg.setVehicleColor(vehicleColor);
        playbackMsg.setDataType(dataType);
        playbackMsg.setDataLength(dataLength);
        playbackMsg.setData(data);
        return playbackMsg;
    }
    /**
     * 远程录像回放请求应答
     *
     * @param ctx
     * @param inferiorPlatformId
     * @param playbackMsg
     */
    public void up_playback_msg_startup_ack(ChannelHandlerContext ctx, Integer inferiorPlatformId, PlaybackMsg playbackMsg) {
        UPPlaybackMsgStartupAck upPlaybackMsgStartupAck = new UPPlaybackMsgStartupAck().decode(playbackMsg);
        upPlaybackMsgStartupAck.setInferiorPlatformId(inferiorPlatformId);
        upPlaybackMsgStartupAck.setCreateTime(LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)));
        upPlaybackMsgStartupAckDao.save(upPlaybackMsgStartupAck);
    }
    /**
     * 远程录像回放控制请求应答
     *
     * @param ctx
     * @param inferiorPlatformId
     * @param playbackMsg
     */
    public void up_playback_msg_control_ack(ChannelHandlerContext ctx, Integer inferiorPlatformId, PlaybackMsg playbackMsg) {
        UPPlaybackMsgControlAck upPlaybackMsgControlAck = new UPPlaybackMsgControlAck().decode(playbackMsg);
        upPlaybackMsgControlAck.setInferiorPlatformId(inferiorPlatformId);
        upPlaybackMsgControlAck.setCreateTime(LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)));
        upPlaybackMsgControlAckDao.save(upPlaybackMsgControlAck);
    }
}
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/RealvideoMsg.java
File was deleted
ruoyi-service/ruoyi-dataInterchange/src/main/java/com/ruoyi/dataInterchange/server/RealvideoMsgService.java
New file
@@ -0,0 +1,119 @@
package com.ruoyi.dataInterchange.server;
import com.ruoyi.dataInterchange.dao.UPRealvideoMsgEndAckDao;
import com.ruoyi.dataInterchange.dao.UPRealvideoMsgStartupAckDao;
import com.ruoyi.dataInterchange.model.RealVideoMsg;
import com.ruoyi.dataInterchange.model.UPRealvideoMsgEndAck;
import com.ruoyi.dataInterchange.model.UPRealvideoMsgStartupAck;
import com.ruoyi.dataInterchange.model.enu.DataType;
import com.ruoyi.dataInterchange.util.jtt809.common.Jtt809Util;
import com.ruoyi.dataInterchange.util.jtt809.packet.common.OuterPacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
/**
 * 主链路实时音视频交互
 *
 * @author zhibing.pu
 * @Date 2025/3/21 11:58
 */
@Slf4j
@Service
public class RealvideoMsgService {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private UPRealvideoMsgStartupAckDao upRealvideoMsgStartupAckDao;
    @Resource
    private UPRealvideoMsgEndAckDao upRealvideoMsgEndAckDao;
    public void up_realvideo_msg(ChannelHandlerContext ctx, OuterPacket out) {
        if (!redisTemplate.hasKey("login:" + out.getGnsscenterId())) {
            log.error("链路还未登录校验,拒绝连接");
            ctx.close();
            return;
        }
        RealVideoMsg realVideoMsg = getRealVideoMsg(out);
        DataType dataType = DataType.getDataType(realVideoMsg.getDataType());
        switch (dataType) {
            case UP_REALVIDEO_MSG_STARTUP_ACK:
                log.info("实时音视频请求应答({}):{}", DataType.UP_REALVIDEO_MSG_STARTUP_ACK.getCode(), out);
                up_realvideo_msg_startup_ack(ctx, out.getGnsscenterId(), realVideoMsg);
                break;
            case UP_REALVIDEO_MSG_END_ACK:
                log.info("主动请求停止实时音视频应答({}):{}", DataType.UP_REALVIDEO_MSG_END_ACK.getCode(), out);
                up_realvideo_msg_end_ack(ctx, out.getGnsscenterId(), realVideoMsg);
                break;
            default:
                break;
        }
    }
    public RealVideoMsg getRealVideoMsg(OuterPacket out) {
        byte[] body = out.getBody();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(body);
        //车牌号
        String vehicleNo = Jtt809Util.readGBKString(byteBuf, 21);
        //车牌颜色
        byte vehicleColor = byteBuf.readByte();
        //子业务类型标识
        int dataType = byteBuf.readUnsignedShort();
        //后续数据长度
        int dataLength = byteBuf.readInt();
        //子业务数据包
        byte[] data = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(data);
        RealVideoMsg realVideoMsg = new RealVideoMsg();
        realVideoMsg.setVehicleNo(vehicleNo);
        realVideoMsg.setVehicleColor(vehicleColor);
        realVideoMsg.setDataType(dataType);
        realVideoMsg.setDataLength(dataLength);
        realVideoMsg.setData(data);
        return realVideoMsg;
    }
    /**
     * 实时音视频请求应答
     *
     * @param ctx
     * @param inferiorPlatformId
     * @param realVideoMsg
     */
    public void up_realvideo_msg_startup_ack(ChannelHandlerContext ctx, Integer inferiorPlatformId, RealVideoMsg realVideoMsg) {
        UPRealvideoMsgStartupAck upRealvideoMsgStartupAck = new UPRealvideoMsgStartupAck().decode(realVideoMsg);
        upRealvideoMsgStartupAck.setInferiorPlatformId(inferiorPlatformId);
        upRealvideoMsgStartupAck.setCreateTime(LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)));
        upRealvideoMsgStartupAckDao.save(upRealvideoMsgStartupAck);
    }
    /**
     * 主动停止实时音视频应答
     *
     * @param ctx
     * @param inferiorPlatformId
     * @param realVideoMsg
     */
    public void up_realvideo_msg_end_ack(ChannelHandlerContext ctx, Integer inferiorPlatformId, RealVideoMsg realVideoMsg) {
        UPRealvideoMsgEndAck upRealvideoMsgEndAck = new UPRealvideoMsgEndAck().decode(realVideoMsg);
        upRealvideoMsgEndAck.setInferiorPlatformId(inferiorPlatformId);
        upRealvideoMsgEndAck.setCreateTime(LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)));
        upRealvideoMsgEndAckDao.save(upRealvideoMsgEndAck);
    }
}