合并主线

This commit is contained in:
648540858
2023-05-25 17:28:57 +08:00
129 changed files with 5909 additions and 2399 deletions

View File

@@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.service.IInviteStreamService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
@@ -62,6 +63,9 @@ public class DeviceQuery {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IInviteStreamService inviteStreamService;
@Autowired
private SIPCommander cmder;
@@ -184,7 +188,7 @@ public class DeviceQuery {
// 清除redis记录
boolean isSuccess = deviceService.delete(deviceId);
if (isSuccess) {
redisCatchStorage.clearCatchByDeviceId(deviceId);
inviteStreamService.clearInviteInfo(deviceId);
// 停止此设备的订阅更新
Set<String> allKeys = dynamicTask.getAllKeys();
for (String key : allKeys) {

View File

@@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.vmanager.gb28181.play;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.InviteSessionStatus;
import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
@@ -14,12 +17,17 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IInviteStreamService;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.vmanager.bean.*;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -60,6 +68,9 @@ public class PlayController {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IInviteStreamService inviteStreamService;
@Autowired
private ZLMRESTfulUtils zlmresTfulUtils;
@@ -89,14 +100,12 @@ public class PlayController {
Device device = storager.queryVideoDevice(deviceId);
MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
RequestMessage msg = new RequestMessage();
RequestMessage requestMessage = new RequestMessage();
String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
boolean exist = resultHolder.exist(key, null);
msg.setKey(key);
requestMessage.setKey(key);
String uuid = UUID.randomUUID().toString();
msg.setId(uuid);
requestMessage.setId(uuid);
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
DeferredResultEx<WVPResult<StreamContent>> deferredResultEx = new DeferredResultEx<>(result);
result.onTimeout(()->{
logger.info("点播接口等待超时");
@@ -104,32 +113,33 @@ public class PlayController {
WVPResult<StreamInfo> wvpResult = new WVPResult<>();
wvpResult.setCode(ErrorCode.ERROR100.getCode());
wvpResult.setMsg("点播超时");
msg.setData(wvpResult);
resultHolder.invokeResult(msg);
requestMessage.setData(wvpResult);
resultHolder.invokeResult(requestMessage);
});
// TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误
deferredResultEx.setFilter(result1 -> {
WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1;
WVPResult<StreamContent> resultStream = new WVPResult<>();
resultStream.setCode(wvpResult1.getCode());
resultStream.setMsg(wvpResult1.getMsg());
if (wvpResult1.getCode() == ErrorCode.SUCCESS.getCode()) {
StreamInfo data = wvpResult1.getData().clone();
if (userSetting.getUseSourceIpAsStreamIp()) {
data.channgeStreamIp(request.getLocalName());
}
resultStream.setData(new StreamContent(wvpResult1.getData()));
}
return resultStream;
});
// 录像查询以channelId作为deviceId查询
resultHolder.put(key, uuid, deferredResultEx);
resultHolder.put(key, uuid, result);
if (!exist) {
playService.play(newMediaServerItem, deviceId, channelId, null, null, null);
}
playService.play(newMediaServerItem, deviceId, channelId, (code, msg, data) -> {
WVPResult<StreamContent> wvpResult = new WVPResult<>();
if (code == InviteErrorCode.SUCCESS.getCode()) {
wvpResult.setCode(ErrorCode.SUCCESS.getCode());
wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
if (data != null) {
StreamInfo streamInfo = (StreamInfo)data;
if (userSetting.getUseSourceIpAsStreamIp()) {
streamInfo.channgeStreamIp(request.getLocalName());
}
wvpResult.setData(new StreamContent(streamInfo));
}
}else {
wvpResult.setCode(code);
wvpResult.setMsg(msg);
}
requestMessage.setData(wvpResult);
resultHolder.invokeResult(requestMessage);
});
return result;
}
@@ -150,21 +160,22 @@ public class PlayController {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备[" + deviceId + "]不存在");
}
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
if (streamInfo == null) {
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
if (inviteInfo == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "点播未找到");
}
try {
logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
cmder.streamByeCmd(device, channelId, streamInfo.getStream(), null, null);
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
try {
logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
cmder.streamByeCmd(device, channelId, inviteInfo.getStream(), null, null);
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
}
redisCatchStorage.stopPlay(streamInfo);
inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
storager.stopPlay(deviceId, channelId);
JSONObject json = new JSONObject();
json.put("deviceId", deviceId);
json.put("channelId", channelId);
@@ -179,15 +190,14 @@ public class PlayController {
@Parameter(name = "streamId", description = "视频流ID", required = true)
@PostMapping("/convert/{streamId}")
public JSONObject playConvert(@PathVariable String streamId) {
StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
if (streamInfo == null) {
streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
}
if (streamInfo == null) {
// StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, streamId);
if (inviteInfo == null || inviteInfo.getStreamInfo() == null) {
logger.warn("视频转码API调用失败, 视频流已经停止!");
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到视频流信息, 视频流可能已经停止");
}
MediaServerItem mediaInfo = mediaServerService.getOne(streamInfo.getMediaServerId());
MediaServerItem mediaInfo = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
if (!rtpInfo.getBoolean("exist")) {
logger.warn("视频转码API调用失败, 视频流已停止推流!");

View File

@@ -1,15 +1,22 @@
package com.genersoft.iot.vmp.vmanager.gb28181.playback;
import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.exception.ServiceException;
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.service.IInviteStreamService;
import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
@@ -20,17 +27,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import java.text.ParseException;
@@ -59,6 +62,9 @@ public class PlaybackController {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IInviteStreamService inviteStreamService;
@Autowired
private IPlayService playService;
@@ -74,8 +80,8 @@ public class PlaybackController {
@Parameter(name = "startTime", description = "开始时间", required = true)
@Parameter(name = "endTime", description = "结束时间", required = true)
@GetMapping("/start/{deviceId}/{channelId}")
public DeferredResult<WVPResult<StreamContent>> start(@PathVariable String deviceId, @PathVariable String channelId,
String startTime, String endTime) {
public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
String startTime, String endTime) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("设备回放 API调用deviceId%s channelId%s", deviceId, channelId));
@@ -86,22 +92,31 @@ public class PlaybackController {
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
resultHolder.put(key, uuid, result);
WVPResult<StreamContent> wvpResult = new WVPResult<>();
RequestMessage requestMessage = new RequestMessage();
requestMessage.setKey(key);
requestMessage.setId(uuid);
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setId(uuid);
playService.playBack(deviceId, channelId, startTime, endTime,
(code, msg, data)->{
playService.playBack(deviceId, channelId, startTime, endTime, null,
playBackResult->{
wvpResult.setCode(playBackResult.getCode());
wvpResult.setMsg(playBackResult.getMsg());
if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {
StreamInfo streamInfo = (StreamInfo)playBackResult.getData();
wvpResult.setData(new StreamContent(streamInfo));
WVPResult<StreamContent> wvpResult = new WVPResult<>();
if (code == InviteErrorCode.SUCCESS.getCode()) {
wvpResult.setCode(ErrorCode.SUCCESS.getCode());
wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
if (data != null) {
StreamInfo streamInfo = (StreamInfo)data;
if (userSetting.getUseSourceIpAsStreamIp()) {
streamInfo.channgeStreamIp(request.getLocalName());
}
wvpResult.setData(new StreamContent(streamInfo));
}
}else {
wvpResult.setCode(code);
wvpResult.setMsg(msg);
}
msg.setData(wvpResult);
resultHolder.invokeResult(msg);
requestMessage.setData(wvpResult);
resultHolder.invokeResult(requestMessage);
});
return result;
@@ -169,14 +184,15 @@ public class PlaybackController {
@GetMapping("/seek/{streamId}/{seekTime}")
public void playSeek(@PathVariable String streamId, @PathVariable long seekTime) {
logger.info("playSeek: "+streamId+", "+seekTime);
StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
if (null == streamInfo) {
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
logger.warn("streamId不存在!");
throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
}
Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
try {
cmder.playSeekCmd(device, streamInfo, seekTime);
cmder.playSeekCmd(device, inviteInfo.getStreamInfo(), seekTime);
} catch (InvalidArgumentException | ParseException | SipException e) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
}
@@ -188,8 +204,9 @@ public class PlaybackController {
@GetMapping("/speed/{streamId}/{speed}")
public void playSpeed(@PathVariable String streamId, @PathVariable Double speed) {
logger.info("playSpeed: "+streamId+", "+speed);
StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
if (null == streamInfo) {
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
logger.warn("streamId不存在!");
throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
}
@@ -197,9 +214,9 @@ public class PlaybackController {
logger.warn("不支持的speed " + speed);
throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持的speed0.25 0.5 1、2、4");
}
Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
try {
cmder.playSpeedCmd(device, streamInfo, speed);
cmder.playSpeedCmd(device, inviteInfo.getStreamInfo(), speed);
} catch (InvalidArgumentException | ParseException | SipException e) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
}

View File

@@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.vmanager.gb28181.record;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
@@ -27,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import java.text.ParseException;
@@ -55,8 +58,8 @@ public class GBRecordController {
@Autowired
private IDeviceService deviceService;
@Autowired
private UserSetting userSetting;
@Operation(summary = "录像查询")
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@@ -119,8 +122,8 @@ public class GBRecordController {
@Parameter(name = "endTime", description = "结束时间", required = true)
@Parameter(name = "downloadSpeed", description = "下载倍速", required = true)
@GetMapping("/download/start/{deviceId}/{channelId}")
public DeferredResult<WVPResult<StreamContent>> download(@PathVariable String deviceId, @PathVariable String channelId,
String startTime, String endTime, String downloadSpeed) {
public DeferredResult<WVPResult<StreamContent>> download(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
String startTime, String endTime, String downloadSpeed) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("历史媒体下载 API调用deviceId%schannelId%sdownloadSpeed%s", deviceId, channelId, downloadSpeed));
@@ -130,22 +133,32 @@ public class GBRecordController {
String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(30000L);
resultHolder.put(key, uuid, result);
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
RequestMessage requestMessage = new RequestMessage();
requestMessage.setId(uuid);
requestMessage.setKey(key);
WVPResult<StreamContent> wvpResult = new WVPResult<>();
playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, playBackResult->{
playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed),
(code, msg, data)->{
wvpResult.setCode(playBackResult.getCode());
wvpResult.setMsg(playBackResult.getMsg());
if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {
StreamInfo streamInfo = (StreamInfo)playBackResult.getData();
wvpResult.setData(new StreamContent(streamInfo));
WVPResult<StreamContent> wvpResult = new WVPResult<>();
if (code == InviteErrorCode.SUCCESS.getCode()) {
wvpResult.setCode(ErrorCode.SUCCESS.getCode());
wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
if (data != null) {
StreamInfo streamInfo = (StreamInfo)data;
if (userSetting.getUseSourceIpAsStreamIp()) {
streamInfo.channgeStreamIp(request.getLocalName());
}
wvpResult.setData(new StreamContent(streamInfo));
}
}else {
wvpResult.setCode(code);
wvpResult.setMsg(msg);
}
msg.setData(wvpResult);
resultHolder.invokeResult(msg);
requestMessage.setData(wvpResult);
resultHolder.invokeResult(requestMessage);
});
return result;

View File

@@ -57,7 +57,7 @@ public class UserController {
if (user == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "用户名或密码错误");
}else {
String jwt = JwtUtils.createToken(username, password);
String jwt = JwtUtils.createToken(username, password, user.getRole().getId());
response.setHeader(JwtUtils.getHeader(), jwt);
user.setAccessToken(jwt);
}