From 0ed395ff2e3d2bcb39ce0bcf24a508ce8a4927c4 Mon Sep 17 00:00:00 2001 From: lin <648540858@qq.com> Date: Tue, 29 Jul 2025 14:46:16 +0800 Subject: [PATCH] =?UTF-8?q?[1078]=20=E6=94=AF=E6=8C=81=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E9=80=9A=E9=81=93=E7=9A=84=E7=82=B9=E6=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CommonChannelController.java | 1 - .../service/IGbChannelPlayService.java | 4 ++ .../impl/GbChannelPlayServiceImpl.java | 53 +++++++++++++- .../iot/vmp/jt1078/proc/request/J0200.java | 2 +- .../jt1078/service/Ijt1078PlayService.java | 7 ++ .../service/impl/jt1078PlayServiceImpl.java | 69 ++++++++++++++++++- web/src/main.js | 7 +- web/src/views/channel/index.vue | 1 + 8 files changed, 134 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java index bb6d2fd34..6d9a66232 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java @@ -307,7 +307,6 @@ public class CommonChannelController { wvpResult.setCode(code); wvpResult.setMsg(msg); } - result.setResult(wvpResult); }else { result.setResult(WVPResult.fail(code, msg)); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelPlayService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelPlayService.java index 1d6e1ebe8..f6fdcc96a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelPlayService.java @@ -21,12 +21,16 @@ public interface IGbChannelPlayService { void playProxy(CommonGBChannel channel, Boolean record, ErrorCallback callback); + void playJt1078(CommonGBChannel channel, Boolean record, ErrorCallback callback); + void stopPlayProxy(CommonGBChannel channel); void playPush(CommonGBChannel channel, String platformDeviceId, String platformName, ErrorCallback callback); void stopPlayPush(CommonGBChannel channel); + void stopPlayJt1078(CommonGBChannel channel); + void pauseRtp(String streamId); void resumeRtp(String streamId); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java index 8a849a28e..86eac2fac 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.bean.PlayException; import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService; import com.genersoft.iot.vmp.gb28181.service.IPlayService; +import com.genersoft.iot.vmp.jt1078.service.Ijt1078PlayService; import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyPlayService; import com.genersoft.iot.vmp.streamPush.service.IStreamPushPlayService; @@ -34,6 +35,9 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { @Autowired private IStreamProxyPlayService streamProxyPlayService; + @Autowired + private Ijt1078PlayService jt1078PlayService; + @Autowired private IStreamPushPlayService streamPushPlayService; @@ -54,6 +58,9 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { if (channel.getDataType() == ChannelDataType.GB28181.value) { // 国标通道 playbackGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), callback); + } else if (channel.getDataType() == ChannelDataType.JT_1078.value) { + // 部标通道 + playbackJtDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), callback); } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) { // 拉流代理 log.warn("[回放通用通道] 不支持回放拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); @@ -78,6 +85,10 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { // 国标通道 downloadGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), downloadSpeed, callback); + } else if (channel.getDataType() == ChannelDataType.JT_1078.value) { + // 部标录像下载 + log.warn("[下载通用通道录像] 不支持下载部标的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.FORBIDDEN, "forbidden"); } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) { // 拉流代理 log.warn("[下载通用通道录像] 不支持下载拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); @@ -109,6 +120,9 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) { // 推流 stopPlayPush(channel); + } else if (channel.getDataType() == ChannelDataType.JT_1078.value) { + // 推流 + stopPlayJt1078(channel); } else { // 通道数据异常 log.error("[点播通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); @@ -116,6 +130,8 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { } } + + @Override public void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback callback) { log.info("[通用通道] 播放, 类型: {}, 编号:{}", channel.getDataType(), channel.getGbDeviceId()); @@ -133,6 +149,9 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { // 推流 playPush(channel, null, null, callback); } + } else if (channel.getDataType() == ChannelDataType.JT_1078.value) { + // 部标设备 + playJt1078(channel, record, callback); } else { // 通道数据异常 log.error("[点播通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); @@ -172,6 +191,18 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { try { streamProxyPlayService.start(channel.getDataDeviceId(), record, callback); }catch (Exception e) { + log.info("[通用通道] 拉流代理点播异常 {}", e.getMessage()); + callback.run(Response.BUSY_HERE, "busy here", null); + } + } + + @Override + public void playJt1078(CommonGBChannel channel, Boolean record, ErrorCallback callback){ + // 部标设备通道 + try { + jt1078PlayService.start(channel.getDataDeviceId(), record, callback); + }catch (Exception e) { + log.info("[通用通道] 部标设备点播异常 {}", e.getMessage()); callback.run(Response.BUSY_HERE, "busy here", null); } } @@ -209,6 +240,16 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { } } + @Override + public void stopPlayJt1078(CommonGBChannel channel) { + // 推流 + try { + jt1078PlayService.stop(channel.getDataDeviceId()); + }catch (Exception e) { + log.error("[停止点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e); + } + } + private void playbackGbDeviceChannel(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback callback){ try { deviceChannelPlayService.playBack(channel, startTime, stopTime, callback); @@ -219,6 +260,16 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { } } + private void playbackJtDeviceChannel(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback callback){ + try { + jt1078PlayService.playBack(channel.getDataDeviceId(), startTime, stopTime, callback); + } catch (PlayException e) { + callback.run(e.getCode(), e.getMsg(), null); + } catch (Exception e) { + callback.run(Response.BUSY_HERE, "busy here", null); + } + } + @Override public void pauseRtp(String streamId) { try { @@ -243,6 +294,4 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { callback.run(Response.BUSY_HERE, "busy here", null); } } - - } diff --git a/src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0200.java b/src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0200.java index c51163852..f42054027 100644 --- a/src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0200.java +++ b/src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0200.java @@ -26,7 +26,7 @@ public class J0200 extends Re { @Override protected Rs decode0(ByteBuf buf, Header header, Session session) { positionInfo = JTPositionBaseInfo.decode(buf); - log.info("[JT-位置汇报]: phoneNumber={} {}", header.getPhoneNumber(), positionInfo.toSimpleString()); + log.debug("[JT-位置汇报]: phoneNumber={} {}", header.getPhoneNumber(), positionInfo.toSimpleString()); // 读取附加信息 // JTPositionAdditionalInfo positionAdditionalInfo = new JTPositionAdditionalInfo(); // Map additionalMsg = new HashMap<>(); diff --git a/src/main/java/com/genersoft/iot/vmp/jt1078/service/Ijt1078PlayService.java b/src/main/java/com/genersoft/iot/vmp/jt1078/service/Ijt1078PlayService.java index 9c7e8cb52..c0f8fd340 100644 --- a/src/main/java/com/genersoft/iot/vmp/jt1078/service/Ijt1078PlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/jt1078/service/Ijt1078PlayService.java @@ -2,8 +2,10 @@ package com.genersoft.iot.vmp.jt1078.service; import com.genersoft.iot.vmp.common.CommonCallback; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.jt1078.bean.*; import com.genersoft.iot.vmp.jt1078.proc.request.J1205; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import java.util.List; @@ -33,4 +35,9 @@ public interface Ijt1078PlayService { void playbackControl(String phoneNumber, Integer channelId, Integer command, Integer playbackSpeed, String time); + void start(Integer channelId, Boolean record, ErrorCallback callback); + + void stop(Integer channelId); + + void playBack(Integer channelId, Long startTime, Long stopTime, ErrorCallback callback); } diff --git a/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java index f549894c8..2d68e69c2 100644 --- a/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java @@ -7,9 +7,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.ftpServer.FtpSetting; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.jt1078.bean.*; import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template; import com.genersoft.iot.vmp.jt1078.event.FtpUploadEvent; @@ -29,6 +27,7 @@ import com.genersoft.iot.vmp.media.event.media.MediaNotFoundEvent; import com.genersoft.iot.vmp.media.event.mediaServer.MediaSendRtpStoppedEvent; import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -45,6 +44,7 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.util.Assert; +import javax.sip.message.Response; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -191,7 +191,12 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { if (channel == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "通道不存在"); } + play(device, channel, type, callback); + } + private void play(JTDevice device, JTChannel channel, int type, CommonCallback> callback) { + String phoneNumber = device.getPhoneNumber(); + int channelId = channel.getId(); String app = "1078"; String stream = phoneNumber + "_" + channelId; // 检查流是否已经存在,存在则返回 @@ -375,6 +380,8 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { return JRecordItemList; } + + @Override public void playback(String phoneNumber, Integer channelId, String startTime, String endTime, Integer type, Integer rate, Integer playbackType, Integer playbackSpeed, CommonCallback> callback) { @@ -387,7 +394,27 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { if (channel == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "通道不存在"); } + playback(device, channel, startTime, endTime, type, rate, playbackType, playbackSpeed, callback); + } + + /** + * 回放 + * @param device 设备 + * @param channel 通道 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @param type 音视频资源类型:0.音视频 1.音频 2.视频 3.视频或音视频 + * @param rate 码流类型:0.所有码流 1.主码流 2.子码流(如果此通道只传输音频,此字段置0) + * @param playbackType 回放方式:0.正常回放 1.快进回放 2.关键帧快退回放 3.关键帧播放 4.单帧上传 + * @param playbackSpeed 快进或快退倍数:0.无效 1.1倍 2.2倍 3.4倍 4.8倍 5.16倍 (回放控制为1和2时,此字段内容有效,否则置0) + * @param callback 结束回调 + */ + private void playback(JTDevice device, JTChannel channel, String startTime, String endTime, Integer type, + Integer rate, Integer playbackType, Integer playbackSpeed, CommonCallback> callback) { + + String phoneNumber = device.getPhoneNumber(); + Integer channelId = channel.getChannelId(); log.info("[JT-回放] 回放,设备:{}, 通道: {}, 开始时间: {}, 结束时间: {}, 音视频类型: {}, 码流类型: {}, " + "回放方式: {}, 快进或快退倍数: {}", phoneNumber, channelId, startTime, endTime, type, rate, playbackType, playbackSpeed); // 检查流是否已经存在,存在则返回 @@ -646,4 +673,40 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { } } } + + @Override + public void start(Integer channelId, Boolean record, ErrorCallback callback) { + JTChannel channel = jt1078Service.getChannelByDbId(channelId); + Assert.notNull(channel, "通道不存在"); + JTDevice device = jt1078Service.getDeviceById(channel.getDataDeviceId()); + Assert.notNull(device, "设备不存在"); + jt1078Template.checkTerminalStatus(device.getPhoneNumber()); + play(device, channel, 0, + result -> callback.run(result.getCode(), result.getMsg(), result.getData())); + } + + @Override + public void stop(Integer channelId) { + JTChannel channel = jt1078Service.getChannelByDbId(channelId); + Assert.notNull(channel, "通道不存在"); + JTDevice device = jt1078Service.getDeviceById(channel.getDataDeviceId()); + Assert.notNull(device, "设备不存在"); + stopPlay(device.getPhoneNumber(), channel.getChannelId()); + } + + @Override + public void playBack(Integer channelId, Long startTime, Long stopTime, ErrorCallback callback) { + if (startTime == null || stopTime == null) { + throw new PlayException(Response.BAD_REQUEST, "bad request"); + } + JTChannel channel = jt1078Service.getChannelByDbId(channelId); + Assert.notNull(channel, "通道不存在"); + JTDevice device = jt1078Service.getDeviceById(channel.getDataDeviceId()); + Assert.notNull(device, "设备不存在"); + jt1078Template.checkTerminalStatus(device.getPhoneNumber()); + String startTimeStr = DateUtil.timestampTo_yyyy_MM_dd_HH_mm_ss(startTime); + String stopTimeStr = DateUtil.timestampTo_yyyy_MM_dd_HH_mm_ss(stopTime); + playback(device, channel, startTimeStr, stopTimeStr, 0, 1, 0, 0, + result -> callback.run(result.getCode(), result.getMsg(), result.getData())); + } } diff --git a/web/src/main.js b/web/src/main.js index 4f72d0d69..2430c79c4 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -40,9 +40,10 @@ Vue.use(VueClipboard) Vue.config.productionTip = false Vue.prototype.$channelTypeList = { - 1: { id: 1, name: '国标设备', style: { color: '#409eff', borderColor: '#b3d8ff' }}, - 2: { id: 2, name: '推流设备', style: { color: '#67c23a', borderColor: '#c2e7b0' }}, - 3: { id: 3, name: '拉流代理', style: { color: '#e6a23c', borderColor: '#f5dab1' }} + 1: { id: 1, name: '国标设备', style: { color: '#409eff', borderColor: '#b3d8ff' } }, + 2: { id: 2, name: '推流设备', style: { color: '#67c23a', borderColor: '#c2e7b0' } }, + 3: { id: 3, name: '拉流代理', style: { color: '#e6a23c', borderColor: '#f5dab1' } }, + 200: { id: 200, name: '部标设备', style: { color: '#36c6fa', borderColor: '#90e3fb' } } } new Vue({ diff --git a/web/src/views/channel/index.vue b/web/src/views/channel/index.vue index 525f33c86..32fed49d6 100755 --- a/web/src/views/channel/index.vue +++ b/web/src/views/channel/index.vue @@ -218,6 +218,7 @@ export default { this.getChannelList() }, getChannelList: function() { + this.channelList = [] this.$store.dispatch('commonChanel/getList', { page: this.currentPage, count: this.count,