Merge branch 'wvp-28181-2.0'

# Conflicts:
#	sql/update.sql
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
This commit is contained in:
648540858
2022-08-09 14:41:21 +08:00
204 changed files with 4646 additions and 1896 deletions

View File

@@ -12,6 +12,7 @@ public class WVPResult<T> {
this.data = data;
}
private int code;
private String msg;
private T data;

View File

@@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
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.service.IDeviceChannelService;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
@@ -52,6 +53,9 @@ public class DeviceQuery {
@Autowired
private IVideoManagerStorage storager;
@Autowired
private IDeviceChannelService deviceChannelService;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@@ -280,7 +284,7 @@ public class DeviceQuery {
})
@PostMapping("/channel/update/{deviceId}")
public ResponseEntity<PageInfo> updateChannel(@PathVariable String deviceId,DeviceChannel channel){
storager.updateChannel(deviceId, channel);
deviceChannelService.updateChannel(deviceId, channel);
return new ResponseEntity<>(null,HttpStatus.OK);
}

View File

@@ -44,7 +44,6 @@ public class GbStreamController {
@ApiImplicitParam(name = "platformId", value = "平台ID", required = true , dataTypeClass = String.class),
@ApiImplicitParam(name = "catalogId", value = "目录ID", required = false , dataTypeClass = String.class),
@ApiImplicitParam(name="query", value = "查询内容", required = false , dataTypeClass = String.class),
@ApiImplicitParam(name="pushing", value = "是否正在推流", required = false , dataTypeClass = Boolean.class),
@ApiImplicitParam(name="mediaServerId", value = "流媒体ID", required = false , dataTypeClass = String.class),
})
@@ -55,7 +54,6 @@ public class GbStreamController {
@RequestParam(required = true)String platformId,
@RequestParam(required = false)String catalogId,
@RequestParam(required = false)String query,
@RequestParam(required = false)Boolean pushing,
@RequestParam(required = false)String mediaServerId){
if (StringUtils.isEmpty(catalogId)) {
catalogId = null;
@@ -69,7 +67,7 @@ public class GbStreamController {
// catalogId 为null 查询未在平台下分配的数据
// catalogId 不为null 查询平台下这个,目录下的通道
return gbStreamService.getAll(page, count, platformId, catalogId, query, pushing, mediaServerId);
return gbStreamService.getAll(page, count, platformId, catalogId, query, mediaServerId);
}

View File

@@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
import com.genersoft.iot.vmp.media.zlm.dto.OnPublishHookParam;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IStreamProxyService;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -37,6 +38,8 @@ public class MediaController {
@Autowired
private IMediaService mediaService;
@Autowired
private IStreamProxyService streamProxyService;
/**
@@ -95,8 +98,30 @@ public class MediaController {
result.setMsg("scccess");
result.setData(streamInfo);
}else {
result.setCode(-1);
result.setMsg("fail");
//获取流失败,重启拉流后重试一次
streamProxyService.stop(app,stream);
boolean start = streamProxyService.start(app, stream);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) {
String host = request.getHeader("Host");
String localAddr = host.split(":")[0];
logger.info("使用{}作为返回流的ip", localAddr);
streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, localAddr, authority);
}else {
streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
}
if (streamInfo != null){
result.setCode(0);
result.setMsg("scccess");
result.setData(streamInfo);
}else {
result.setCode(-1);
result.setMsg("fail");
}
}
return result;
}

View File

@@ -8,7 +8,9 @@ import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
import com.genersoft.iot.vmp.gb28181.bean.TreeType;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.service.IPlatformChannelService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
@@ -48,6 +50,9 @@ public class PlatformController {
@Autowired
private IVideoManagerStorage storager;
@Autowired
private IPlatformChannelService platformChannelService;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@@ -236,6 +241,12 @@ public class PlatformController {
parentPlatform.setCharacterSet(parentPlatform.getCharacterSet().toUpperCase());
ParentPlatform parentPlatformOld = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId());
parentPlatform.setUpdateTime(DateUtil.getNow());
if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) {
// 目录结构发生变化,清空之前的关联关系
logger.info("保存平台{}时发现目录结构变化,清空关联关系", parentPlatform.getDeviceGBId());
storager.cleanContentForPlatform(parentPlatform.getServerGBId());
}
boolean updateResult = storager.updateParentPlatform(parentPlatform);
if (updateResult) {
@@ -256,6 +267,8 @@ public class PlatformController {
}
} else if (parentPlatformOld != null && parentPlatformOld.isEnable() && !parentPlatform.isEnable()) { // 关闭启用时注销
commanderForPlatform.unregister(parentPlatformOld, null, null);
// 停止订阅相关的定时任务
subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());
}
wvpResult.setCode(0);
wvpResult.setMsg("success");
@@ -405,7 +418,7 @@ public class PlatformController {
if (logger.isDebugEnabled()) {
logger.debug("给上级平台添加国标通道API调用");
}
int result = storager.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId());
int result = platformChannelService.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId());
return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
}
@@ -451,13 +464,20 @@ public class PlatformController {
if (logger.isDebugEnabled()) {
logger.debug("查询目录,platformId: {}, parentId: {}", platformId, parentId);
}
ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
if (platform == null) {
return new ResponseEntity<>(new WVPResult<>(400, "平台未找到", null), HttpStatus.OK);
}
if (platformId.equals(parentId)) {
parentId = platform.getDeviceGBId();
}
List<PlatformCatalog> platformCatalogList = storager.getChildrenCatalogByPlatform(platformId, parentId);
// 查询下属的国标通道
// List<PlatformCatalog> catalogsForChannel = storager.queryChannelInParentPlatformAndCatalog(platformId, parentId);
// 查询下属的直播流通道
// List<PlatformCatalog> catalogsForStream = storager.queryStreamInParentPlatformAndCatalog(platformId, parentId);
// platformCatalogList.addAll(catalogsForChannel);
// platformCatalogList.addAll(catalogsForStream);
// if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) {
// platformCatalogList = storager.getChildrenCatalogByPlatform(platformId, parentId);
// }else {
//
// }
WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
result.setCode(0);
result.setMsg("success");
@@ -485,7 +505,6 @@ public class PlatformController {
PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId());
WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
if (platformCatalogInStore != null) {
result.setCode(-1);
result.setMsg(platformCatalog.getId() + " already exists");

View File

@@ -8,6 +8,8 @@ import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.VersionInfo;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
@@ -38,7 +40,7 @@ import java.util.Set;
public class ServerController {
@Autowired
private ConfigurableApplicationContext context;
private ZLMHttpHookSubscribe zlmHttpHookSubscribe;
@Autowired
private IMediaServerService mediaServerService;
@@ -254,6 +256,18 @@ public class ServerController {
return result;
}
@ApiOperation("获取当前所有hook")
@GetMapping(value = "/hooks")
@ResponseBody
public WVPResult<List<IHookSubscribe>> getHooks(){
WVPResult<List<IHookSubscribe>> result = new WVPResult<>();
result.setCode(0);
result.setMsg("success");
List<IHookSubscribe> all = zlmHttpHookSubscribe.getAll();
result.setData(all);
return result;
}
// @ApiOperation("当前进行中的动态任务")
// @GetMapping(value = "/dynamicTask")
// @ResponseBody

View File

@@ -4,6 +4,7 @@ import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.security.SecurityUtils;
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
@@ -63,6 +64,9 @@ public class StreamPushController {
@Autowired
private IMediaService mediaService;
@Autowired
private UserSetting userSetting;
@ApiOperation("推流列表查询")
@ApiImplicitParams({
@ApiImplicitParam(name="page", value = "当前页", required = true, dataTypeClass = Integer.class),
@@ -260,29 +264,63 @@ public class StreamPushController {
})
@GetMapping(value = "/getPlayUrl")
@ResponseBody
public WVPResult<StreamInfo> getPlayUrl(HttpServletRequest request, @RequestParam String app,
@RequestParam String stream,
@RequestParam(required = false) String mediaServerId){
public WVPResult<StreamInfo> getPlayUrl(@RequestParam String app,@RequestParam String stream,
@RequestParam(required = false) String mediaServerId){
boolean authority = false;
// 是否登陆用户, 登陆用户返回完整信息
LoginUser userInfo = SecurityUtils.getUserInfo();
if (userInfo!= null) {
authority = true;
}
StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
WVPResult<StreamInfo> result = new WVPResult<>();
StreamPushItem push = streamPushService.getPush(app, stream);
if (push != null && !push.isSelf()) {
result.setCode(-1);
result.setMsg("来自其他平台的推流信息");
return result;
}
StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
if (streamInfo != null){
result.setCode(0);
result.setMsg("scccess");
result.setMsg("success");
result.setData(streamInfo);
}else {
result.setCode(-1);
result.setMsg("fail");
result.setMsg("获取播放地址失败");
}
return result;
}
/**
* 获取推流播放地址
* @param stream 推流信息
* @return
*/
@ApiOperation("获取推流播放地址")
@ApiImplicitParams({
@ApiImplicitParam(name = "stream", value = "推流信息", dataTypeClass = StreamPushItem.class),
})
@PostMapping(value = "/add")
@ResponseBody
public WVPResult<StreamInfo> add(@RequestBody StreamPushItem stream){
if (StringUtils.isEmpty(stream.getGbId())) {
return new WVPResult<>(400, "国标ID不可为空", null);
}
if (StringUtils.isEmpty(stream.getApp()) && StringUtils.isEmpty(stream.getStream())) {
return new WVPResult<>(400, "app或stream不可为空", null);
}
stream.setStatus(false);
stream.setPushIng(false);
stream.setAliveSecond(0L);
stream.setTotalReaderCount("0");
boolean result = streamPushService.add(stream);
if (result) {
return new WVPResult<>(0, "success", null);
}else {
return new WVPResult<>(-1, "fail", null);
}
}
}

View File

@@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.storager.dao.dto.Role;
import com.genersoft.iot.vmp.storager.dao.dto.User;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@@ -123,7 +124,8 @@ public class UserController {
User user = new User();
user.setUsername(username);
user.setPassword(DigestUtils.md5DigestAsHex(password.getBytes()));
//新增用户的pushKey的生成规则为md5(时间戳+用户名)
user.setPushKey(DigestUtils.md5DigestAsHex((System.currentTimeMillis()+password).getBytes()));
Role role = roleService.getRoleById(roleId);
if (role == null) {
@@ -137,6 +139,7 @@ public class UserController {
user.setUpdateTime(DateUtil.getNow());
int addResult = userService.addUser(user);
result.setCode(addResult > 0 ? 0 : -1);
result.setMsg(addResult > 0 ? "success" : "fail");
result.setData(addResult);
@@ -177,4 +180,68 @@ public class UserController {
result.setData(allUsers);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* 分页查询用户
*
* @param page 当前页
* @param count 每页查询数量
* @return 分页用户列表
*/
@ApiOperation("分页查询用户")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "当前页", required = true, dataTypeClass = Integer.class),
@ApiImplicitParam(name = "count", value = "每页查询数量", required = true, dataTypeClass = Integer.class),
})
@GetMapping("/users")
public PageInfo<User> users(int page, int count) {
return userService.getUsers(page, count);
}
@ApiOperation("修改pushkey")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId", required = true, value = "用户Id", dataTypeClass = Integer.class),
@ApiImplicitParam(name = "pushKey", required = true, value = "新的pushKey", dataTypeClass = String.class),
})
@RequestMapping("/changePushKey")
public ResponseEntity<WVPResult<String>> changePushKey(@RequestParam Integer userId,@RequestParam String pushKey) {
// 获取当前登录用户id
int currenRoleId = SecurityUtils.getUserInfo().getRole().getId();
WVPResult<String> result = new WVPResult<>();
if (currenRoleId != 1) {
// 只用角色id为0才可以删除和添加用户
result.setCode(-1);
result.setMsg("用户无权限");
return new ResponseEntity<>(result, HttpStatus.FORBIDDEN);
}
int resetPushKeyResult = userService.changePushKey(userId,pushKey);
result.setCode(resetPushKeyResult > 0 ? 0 : -1);
result.setMsg(resetPushKeyResult > 0 ? "success" : "fail");
return new ResponseEntity<>(result, HttpStatus.OK);
}
@ApiOperation("管理员修改普通用户密码")
@ApiImplicitParams({
@ApiImplicitParam(name = "adminId", required = true, value = "管理员id", dataTypeClass = String.class),
@ApiImplicitParam(name = "userId", required = true, value = "用户id", dataTypeClass = String.class),
@ApiImplicitParam(name = "password", required = true, value = "新密码未md5加密的密码", dataTypeClass = String.class),
})
@PostMapping("/changePasswordForAdmin")
public String changePasswordForAdmin(@RequestParam int userId, @RequestParam String password) {
// 获取当前登录用户id
LoginUser userInfo = SecurityUtils.getUserInfo();
if (userInfo == null) {
return "fail";
}
Role role = userInfo.getRole();
if (role != null && role.getId() == 1) {
boolean result = userService.changePassword(userId, DigestUtils.md5DigestAsHex(password.getBytes()));
if (result) {
return "success";
}
}
return "fail";
}
}