支持多WVP的推流播放

pull/1642/head
648540858 2024-08-09 16:27:08 +08:00
parent 7f8a15f017
commit 16708e385b
22 changed files with 203 additions and 129 deletions

View File

@ -414,4 +414,46 @@ public interface CommonGBChannelMapper {
" </script>"}) " </script>"})
int updateGroup(@Param("parentId") String parentId, @Param("businessGroup") String businessGroup, int updateGroup(@Param("parentId") String parentId, @Param("businessGroup") String businessGroup,
List<CommonGBChannel> channelList); List<CommonGBChannel> channelList);
@Update({"<script>" +
"<foreach collection='commonGBChannels' item='item' separator=';'>" +
" UPDATE" +
" wvp_device_channel" +
" SET update_time=#{item.updateTime}" +
", gb_device_id=#{item.gbDeviceId}" +
", gb_name=#{item.gbName}" +
", gb_manufacturer=#{item.gbManufacturer}" +
", gb_model=#{item.gbModel}" +
", gb_owner=#{item.gbOwner}" +
", gb_civil_code=#{item.gbCivilCode}" +
", gb_block=#{item.gbBlock}" +
", gb_address=#{item.gbAddress}" +
", gb_parental=#{item.gbParental}" +
", gb_safety_way=#{item.gbSafetyWay}" +
", gb_register_way=#{item.gbRegisterWay}" +
", gb_cert_num=#{item.gbCertNum}" +
", gb_certifiable=#{item.gbCertifiable}" +
", gb_err_code=#{item.gbErrCode}" +
", gb_end_time=#{item.gbEndTime}" +
", gb_ip_address=#{item.gbIpAddress}" +
", gb_port=#{item.gbPort}" +
", gb_password=#{item.gbPassword}" +
", gb_status=#{item.gbStatus}" +
", gb_longitude=#{item.gbLongitude}" +
", gb_latitude=#{item.gbLatitude}" +
", gb_ptz_type=#{item.gbPtzType}" +
", gb_position_type=#{item.gbPositionType}" +
", gb_room_type=#{item.gbRoomType}" +
", gb_use_type=#{item.gbUseType}" +
", gb_supply_light_type=#{item.gbSupplyLightType}" +
", gb_direction_type=#{item.gbDirectionType}" +
", gb_resolution=#{item.gbResolution}" +
", gb_business_group_id=#{item.gbBusinessGroupId}" +
", gb_download_speed=#{item.gbDownloadSpeed}" +
", gb_svc_space_support_mod=#{item.gbSvcSpaceSupportMod}" +
", gb_svc_time_support_mode=#{item.gbSvcTimeSupportMode}" +
" WHERE id=#{item.id}" +
"</foreach>" +
"</script>"})
int batchUpdate(List<CommonGBChannel> commonGBChannels);
} }

View File

@ -73,4 +73,6 @@ public interface IGbChannelService {
void addChannelToGroupByGbDevice(String parentId, String businessGroup, List<Integer> deviceIds); void addChannelToGroupByGbDevice(String parentId, String businessGroup, List<Integer> deviceIds);
void deleteChannelToGroupByGbDevice(List<Integer> deviceIds); void deleteChannelToGroupByGbDevice(List<Integer> deviceIds);
void batchUpdate(List<CommonGBChannel> commonGBChannels);
} }

View File

@ -238,6 +238,36 @@ public class GbChannelServiceImpl implements IGbChannelService {
log.warn("[新增多个通道] 通道数量为{},成功保存:{}", commonGBChannels.size(), result); log.warn("[新增多个通道] 通道数量为{},成功保存:{}", commonGBChannels.size(), result);
} }
@Override
public void batchUpdate(List<CommonGBChannel> commonGBChannels) {
if (commonGBChannels.isEmpty()) {
log.warn("[更新多个通道] 通道数量为0更新失败");
return;
}
// 批量保存
int limitCount = 1000;
int result = 0;
if (commonGBChannels.size() > limitCount) {
for (int i = 0; i < commonGBChannels.size(); i += limitCount) {
int toIndex = i + limitCount;
if (i + limitCount > commonGBChannels.size()) {
toIndex = commonGBChannels.size();
}
result += commonGBChannelMapper.batchUpdate(commonGBChannels.subList(i, toIndex));
}
}else {
result += commonGBChannelMapper.batchUpdate(commonGBChannels);
}
log.warn("[更新多个通道] 通道数量为{},成功保存:{}", commonGBChannels.size(), result);
// 发送通过更新通知
try {
// 发送通知
eventPublisher.catalogEventPublish(null, commonGBChannels, CatalogEvent.UPDATE);
}catch (Exception e) {
log.warn("[更新多个通道] 发送失败,{}个", commonGBChannels.size(), e);
}
}
@Override @Override
@Transactional @Transactional
public void updateStatus(List<CommonGBChannel> commonGBChannels) { public void updateStatus(List<CommonGBChannel> commonGBChannels) {
@ -259,11 +289,17 @@ public class GbChannelServiceImpl implements IGbChannelService {
result += commonGBChannelMapper.updateStatus(commonGBChannels); result += commonGBChannelMapper.updateStatus(commonGBChannels);
} }
log.warn("[更新多个通道状态] 通道数量为{},成功保存:{}", commonGBChannels.size(), result); log.warn("[更新多个通道状态] 通道数量为{},成功保存:{}", commonGBChannels.size(), result);
// 发送通过更新通知
try {
// 发送通知
eventPublisher.catalogEventPublish(null, commonGBChannels, CatalogEvent.UPDATE);
}catch (Exception e) {
log.warn("[更新多个通道] 发送失败,{}个", commonGBChannels.size(), e);
}
} }
@Override @Override
public List<CommonGBChannel> queryByPlatformId(Integer platformId) { public List<CommonGBChannel> queryByPlatformId(Integer platformId) {
return commonGBChannelMapper.queryByPlatformId(platformId); return commonGBChannelMapper.queryByPlatformId(platformId);
} }

View File

@ -523,7 +523,7 @@ public class PlayServiceImpl implements IPlayService {
streamSession.remove(device.getDeviceId(), channel.getDeviceId(), ssrcInfo.getStream()); streamSession.remove(device.getDeviceId(), channel.getDeviceId(), ssrcInfo.getStream());
mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
// 取消订阅消息监听 // 取消订阅消息监听
subscribe.removeSubscribe(Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcInfo.getStream(), mediaServerItem.getId())); subscribe.removeSubscribe(Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcInfo.getStream()));
} }
}else { }else {
log.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流:{},端口:{}, SSRC: {}", log.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流:{},端口:{}, SSRC: {}",

View File

@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.service.IPlayService;
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
@ -24,11 +25,8 @@ import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.event.hook.Hook; import com.genersoft.iot.vmp.media.event.hook.Hook;
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.event.hook.HookType;
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.service.IMediaServerService;
import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
import com.genersoft.iot.vmp.gb28181.service.IPlayService;
import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
@ -598,10 +596,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
sendRtpItem.setPlayType(InviteStreamType.PUSH); sendRtpItem.setPlayType(InviteStreamType.PUSH);
if (streamPushItem != null) { if (streamPushItem != null) {
// 从redis查询是否正在接收这个推流 // 从redis查询是否正在接收这个推流
MediaArrivalEvent mediaArrivalEvent = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream()); MediaInfo mediaInfo = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream());
if (mediaArrivalEvent != null) { if (mediaInfo != null) {
sendRtpItem.setServerId(mediaArrivalEvent.getServerId()); sendRtpItem.setServerId(mediaInfo.getServerId());
sendRtpItem.setMediaServerId(mediaArrivalEvent.getMediaServer().getId()); sendRtpItem.setMediaServerId(mediaInfo.getMediaServer().getId());
redisCatchStorage.updateSendRTPSever(sendRtpItem); redisCatchStorage.updateSendRTPSever(sendRtpItem);
// 开始推流 // 开始推流

View File

@ -3,10 +3,12 @@ package com.genersoft.iot.vmp.media.bean;
import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
import com.genersoft.iot.vmp.utils.MediaServerUtils;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* *
@ -51,10 +53,15 @@ public class MediaInfo {
private Long bytesSpeed; private Long bytesSpeed;
@Schema(description = "鉴权参数") @Schema(description = "鉴权参数")
private String callId; private String callId;
@Schema(description = "额外参数")
private Map<String, String> paramMap;
@Schema(description = "服务ID")
private String serverId;
public static MediaInfo getInstance(JSONObject jsonObject, MediaServer mediaServer) { public static MediaInfo getInstance(JSONObject jsonObject, MediaServer mediaServer, String serverId) {
MediaInfo mediaInfo = new MediaInfo(); MediaInfo mediaInfo = new MediaInfo();
mediaInfo.setMediaServer(mediaServer); mediaInfo.setMediaServer(mediaServer);
mediaInfo.setServerId(serverId);
String app = jsonObject.getString("app"); String app = jsonObject.getString("app");
mediaInfo.setApp(app); mediaInfo.setApp(app);
String stream = jsonObject.getString("stream"); String stream = jsonObject.getString("stream");
@ -66,6 +73,7 @@ public class MediaInfo {
Integer originType = jsonObject.getInteger("originType"); Integer originType = jsonObject.getInteger("originType");
String originUrl = jsonObject.getString("originUrl"); String originUrl = jsonObject.getString("originUrl");
Long aliveSecond = jsonObject.getLong("aliveSecond"); Long aliveSecond = jsonObject.getLong("aliveSecond");
String params = jsonObject.getString("params");
Long bytesSpeed = jsonObject.getLong("bytesSpeed"); Long bytesSpeed = jsonObject.getLong("bytesSpeed");
if (totalReaderCount != null) { if (totalReaderCount != null) {
mediaInfo.setReaderCount(totalReaderCount); mediaInfo.setReaderCount(totalReaderCount);
@ -86,6 +94,12 @@ public class MediaInfo {
if (bytesSpeed != null) { if (bytesSpeed != null) {
mediaInfo.setBytesSpeed(bytesSpeed); mediaInfo.setBytesSpeed(bytesSpeed);
} }
if (params != null) {
mediaInfo.setParamMap(MediaServerUtils.urlParamToMap(params));
if(mediaInfo.getCallId() == null) {
mediaInfo.setCallId(mediaInfo.getParamMap().get("callId"));
}
}
JSONArray jsonArray = jsonObject.getJSONArray("tracks"); JSONArray jsonArray = jsonObject.getJSONArray("tracks");
if (jsonArray.isEmpty()) { if (jsonArray.isEmpty()) {
return null; return null;
@ -137,7 +151,7 @@ public class MediaInfo {
return mediaInfo; return mediaInfo;
} }
public static MediaInfo getInstance(OnStreamChangedHookParam param, MediaServer mediaServer) { public static MediaInfo getInstance(OnStreamChangedHookParam param, MediaServer mediaServer, String serverId) {
MediaInfo mediaInfo = new MediaInfo(); MediaInfo mediaInfo = new MediaInfo();
mediaInfo.setApp(param.getApp()); mediaInfo.setApp(param.getApp());
@ -150,6 +164,11 @@ public class MediaInfo {
mediaInfo.setOriginUrl(param.getOriginUrl()); mediaInfo.setOriginUrl(param.getOriginUrl());
mediaInfo.setAliveSecond(param.getAliveSecond()); mediaInfo.setAliveSecond(param.getAliveSecond());
mediaInfo.setBytesSpeed(param.getBytesSpeed()); mediaInfo.setBytesSpeed(param.getBytesSpeed());
mediaInfo.setParamMap(param.getParamMap());
if(mediaInfo.getCallId() == null) {
mediaInfo.setCallId(param.getParamMap().get("callId"));
}
mediaInfo.setServerId(serverId);
List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
if (tracks == null || tracks.isEmpty()) { if (tracks == null || tracks.isEmpty()) {
return mediaInfo; return mediaInfo;

View File

@ -1,9 +1,12 @@
package com.genersoft.iot.vmp.media.event.hook; package com.genersoft.iot.vmp.media.event.hook;
import lombok.Data;
/** /**
* zlm hook * zlm hook
* @author lin * @author lin
*/ */
@Data
public class Hook { public class Hook {
private HookType hookType; private HookType hookType;
@ -12,60 +15,21 @@ public class Hook {
private String stream; private String stream;
private String mediaServerId;
private Long expireTime; private Long expireTime;
public static Hook getInstance(HookType hookType, String app, String stream, String mediaServerId) { public static Hook getInstance(HookType hookType, String app, String stream) {
Hook hookSubscribe = new Hook(); Hook hookSubscribe = new Hook();
hookSubscribe.setApp(app); hookSubscribe.setApp(app);
hookSubscribe.setStream(stream); hookSubscribe.setStream(stream);
hookSubscribe.setHookType(hookType); hookSubscribe.setHookType(hookType);
hookSubscribe.setMediaServerId(mediaServerId);
hookSubscribe.setExpireTime(System.currentTimeMillis() + 5 * 60 * 1000); hookSubscribe.setExpireTime(System.currentTimeMillis() + 5 * 60 * 1000);
return hookSubscribe; return hookSubscribe;
} }
public HookType getHookType() { public static Hook getInstance(HookType hookType, String app, String stream, String mediaServer) {
return hookType; // TODO 后续修改所有方法
} return Hook.getInstance(hookType, app, stream);
public void setHookType(HookType hookType) {
this.hookType = hookType;
}
public String getApp() {
return app;
}
public void setApp(String app) {
this.app = app;
}
public String getStream() {
return stream;
}
public void setStream(String stream) {
this.stream = stream;
}
public Long getExpireTime() {
return expireTime;
}
public void setExpireTime(Long expireTime) {
this.expireTime = expireTime;
}
public String getMediaServerId() {
return mediaServerId;
}
public void setMediaServerId(String mediaServerId) {
this.mediaServerId = mediaServerId;
} }
@Override @Override
@ -74,8 +38,7 @@ public class Hook {
Hook param = (Hook) obj; Hook param = (Hook) obj;
return param.getHookType().equals(this.hookType) return param.getHookType().equals(this.hookType)
&& param.getApp().equals(this.app) && param.getApp().equals(this.app)
&& param.getStream().equals(this.stream) && param.getStream().equals(this.stream);
&& param.getMediaServerId().equals(this.mediaServerId);
}else { }else {
return false; return false;
} }
@ -83,6 +46,6 @@ public class Hook {
@Override @Override
public String toString() { public String toString() {
return this.getHookType() + this.getApp() + this.getStream() + this.getMediaServerId(); return this.getHookType() + this.getApp() + this.getStream();
} }
} }

View File

@ -70,11 +70,13 @@ public class HookSubscribe {
private final Map<String, Hook> allHook = new ConcurrentHashMap<>(); private final Map<String, Hook> allHook = new ConcurrentHashMap<>();
private void sendNotify(HookType hookType, MediaEvent event) { private void sendNotify(HookType hookType, MediaEvent event) {
Hook paramHook = Hook.getInstance(hookType, event.getApp(), event.getStream(), event.getMediaServer().getId()); Hook paramHook = Hook.getInstance(hookType, event.getApp(), event.getStream());
Event hookSubscribeEvent = allSubscribes.get(paramHook.toString()); Event hookSubscribeEvent = allSubscribes.get(paramHook.toString());
if (hookSubscribeEvent != null) { if (hookSubscribeEvent != null) {
HookData data = HookData.getInstance(event); HookData data = HookData.getInstance(event);
hookSubscribeEvent.response(data); hookSubscribeEvent.response(data);
}else {
} }
} }

View File

@ -4,7 +4,6 @@ import com.genersoft.iot.vmp.media.bean.MediaInfo;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
import lombok.Data;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -19,15 +18,14 @@ public class MediaArrivalEvent extends MediaEvent {
super(source); super(source);
} }
public static MediaArrivalEvent getInstance(Object source, OnStreamChangedHookParam hookParam, MediaServer mediaServer){ public static MediaArrivalEvent getInstance(Object source, OnStreamChangedHookParam hookParam, MediaServer mediaServer, String serverId){
MediaArrivalEvent mediaArrivalEvent = new MediaArrivalEvent(source); MediaArrivalEvent mediaArrivalEvent = new MediaArrivalEvent(source);
mediaArrivalEvent.setMediaInfo(MediaInfo.getInstance(hookParam, mediaServer)); mediaArrivalEvent.setMediaInfo(MediaInfo.getInstance(hookParam, mediaServer, serverId));
mediaArrivalEvent.setApp(hookParam.getApp()); mediaArrivalEvent.setApp(hookParam.getApp());
mediaArrivalEvent.setStream(hookParam.getStream()); mediaArrivalEvent.setStream(hookParam.getStream());
mediaArrivalEvent.setMediaServer(mediaServer); mediaArrivalEvent.setMediaServer(mediaServer);
mediaArrivalEvent.setSchema(hookParam.getSchema()); mediaArrivalEvent.setSchema(hookParam.getSchema());
mediaArrivalEvent.setSchema(hookParam.getSchema()); mediaArrivalEvent.setSchema(hookParam.getSchema());
mediaArrivalEvent.setHookParam(hookParam);
mediaArrivalEvent.setParamMap(hookParam.getParamMap()); mediaArrivalEvent.setParamMap(hookParam.getParamMap());
return mediaArrivalEvent; return mediaArrivalEvent;
} }
@ -40,10 +38,6 @@ public class MediaArrivalEvent extends MediaEvent {
@Setter @Setter
private String callId; private String callId;
@Getter
@Setter
private OnStreamChangedHookParam hookParam;
@Getter @Getter
@Setter @Setter
private StreamContent streamInfo; private StreamContent streamInfo;

View File

@ -156,7 +156,7 @@ public class ZLMHttpHookListener {
}else { }else {
param.setParamMap(new HashMap<>()); param.setParamMap(new HashMap<>());
} }
MediaArrivalEvent mediaArrivalEvent = MediaArrivalEvent.getInstance(this, param, mediaServer); MediaArrivalEvent mediaArrivalEvent = MediaArrivalEvent.getInstance(this, param, mediaServer, userSetting.getServerId());
applicationEventPublisher.publishEvent(mediaArrivalEvent); applicationEventPublisher.publishEvent(mediaArrivalEvent);
} else { } else {
log.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); log.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());

View File

@ -5,6 +5,7 @@ import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.CommonCallback; import com.genersoft.iot.vmp.common.CommonCallback;
import com.genersoft.iot.vmp.common.StreamInfo; 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.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaInfo;
@ -35,6 +36,9 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
@Autowired @Autowired
private ZLMServerFactory zlmServerFactory; private ZLMServerFactory zlmServerFactory;
@Autowired
private UserSetting userSetting;
@Override @Override
public int createRTPServer(MediaServer mediaServer, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode) { public int createRTPServer(MediaServer mediaServer, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode) {
return zlmServerFactory.createRTPServer(mediaServer, streamId, ssrc, port, onlyAuto, reUsePort, tcpMode); return zlmServerFactory.createRTPServer(mediaServer, streamId, ssrc, port, onlyAuto, reUsePort, tcpMode);
@ -181,7 +185,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
return null; return null;
} }
JSONObject mediaJSON = data.getJSONObject(0); JSONObject mediaJSON = data.getJSONObject(0);
MediaInfo mediaInfo = MediaInfo.getInstance(mediaJSON, mediaServer); MediaInfo mediaInfo = MediaInfo.getInstance(mediaJSON, mediaServer, userSetting.getServerId());
StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, app, stream, mediaInfo, callId, true); StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, app, stream, mediaInfo, callId, true);
if (streamInfo != null) { if (streamInfo != null) {
streamInfoList.add(streamInfo); streamInfoList.add(streamInfo);
@ -234,7 +238,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
if (jsonObject.getInteger("code") != 0) { if (jsonObject.getInteger("code") != 0) {
return null; return null;
} }
return MediaInfo.getInstance(jsonObject, mediaServer); return MediaInfo.getInstance(jsonObject, mediaServer, userSetting.getServerId());
} }
@Override @Override

View File

@ -166,7 +166,7 @@ public class RedisRpcController {
/** /**
* 线 * 线
*/ */
public RedisRpcResponse onPushStreamOnlineEvent(RedisRpcRequest request) { public RedisRpcResponse onStreamOnlineEvent(RedisRpcRequest request) {
StreamInfo streamInfo = JSONObject.parseObject(request.getParam().toString(), StreamInfo.class); StreamInfo streamInfo = JSONObject.parseObject(request.getParam().toString(), StreamInfo.class);
log.info("[redis-rpc] 监听流上线: {}/{}", streamInfo.getApp(), streamInfo.getStream()); log.info("[redis-rpc] 监听流上线: {}/{}", streamInfo.getApp(), streamInfo.getStream());
// 查询本级是否有这个流 // 查询本级是否有这个流

View File

@ -158,11 +158,11 @@ public class RedisRpcServiceImpl implements IRedisRpcService {
log.info("[请求所有WVP监听流上线] {}/{}", app, stream); log.info("[请求所有WVP监听流上线] {}/{}", app, stream);
// 监听流上线。 流上线直接发送sendRtpItem消息给实际的信令处理者 // 监听流上线。 流上线直接发送sendRtpItem消息给实际的信令处理者
Hook hook = Hook.getInstance(HookType.on_media_arrival, app, stream, null); Hook hook = Hook.getInstance(HookType.on_media_arrival, app, stream);
StreamInfo streamInfoParam = new StreamInfo(); StreamInfo streamInfoParam = new StreamInfo();
streamInfoParam.setApp(app); streamInfoParam.setApp(app);
streamInfoParam.setStream(stream); streamInfoParam.setStream(stream);
RedisRpcRequest request = buildRequest("onPushStreamOnlineEvent", streamInfoParam); RedisRpcRequest request = buildRequest("onStreamOnlineEvent", streamInfoParam);
hookSubscribe.addSubscribe(hook, (hookData) -> { hookSubscribe.addSubscribe(hook, (hookData) -> {
if (callback != null) { if (callback != null) {
callback.run(mediaServerService.getStreamInfoByAppAndStream(hookData.getMediaServer(), callback.run(mediaServerService.getStreamInfoByAppAndStream(hookData.getMediaServer(),

View File

@ -5,9 +5,7 @@ import com.genersoft.iot.vmp.common.SystemAllInfo;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaInfo;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
@ -214,9 +212,9 @@ public interface IRedisCatchStorage {
void sendPlatformStopPlayMsg(SendRtpItem sendRtpItem, ParentPlatform platform); void sendPlatformStopPlayMsg(SendRtpItem sendRtpItem, ParentPlatform platform);
void addPushListItem(String app, String stream, MediaArrivalEvent param); void addPushListItem(String app, String stream, MediaInfo param);
MediaArrivalEvent getPushListItem(String app, String stream); MediaInfo getPushListItem(String app, String stream);
void removePushListItem(String app, String stream, String mediaServerId); void removePushListItem(String app, String stream, String mediaServerId);

View File

@ -10,9 +10,7 @@ import com.genersoft.iot.vmp.gb28181.dao.DeviceChannelMapper;
import com.genersoft.iot.vmp.gb28181.dao.DeviceMapper; import com.genersoft.iot.vmp.gb28181.dao.DeviceMapper;
import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaInfo;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@ -690,22 +688,22 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
} }
@Override @Override
public void addPushListItem(String app, String stream, MediaArrivalEvent event) { public void addPushListItem(String app, String stream, MediaInfo mediaInfo) {
String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream; String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream;
redisTemplate.opsForValue().set(key, event); redisTemplate.opsForValue().set(key, mediaInfo);
} }
@Override @Override
public MediaArrivalEvent getPushListItem(String app, String stream) { public MediaInfo getPushListItem(String app, String stream) {
String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream; String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream;
return (MediaArrivalEvent)redisTemplate.opsForValue().get(key); return (MediaInfo)redisTemplate.opsForValue().get(key);
} }
@Override @Override
public void removePushListItem(String app, String stream, String mediaServerId) { public void removePushListItem(String app, String stream, String mediaServerId) {
String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream; String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream;
OnStreamChangedHookParam param = (OnStreamChangedHookParam)redisTemplate.opsForValue().get(key); MediaInfo param = (MediaInfo)redisTemplate.opsForValue().get(key);
if (param != null && param.getMediaServerId().equalsIgnoreCase(mediaServerId)) { if (param != null && param.getMediaServer().getId().equalsIgnoreCase(mediaServerId)) {
redisTemplate.delete(key); redisTemplate.delete(key);
} }
} }

View File

@ -13,8 +13,8 @@ import java.util.Set;
@Repository @Repository
public interface StreamPushMapper { public interface StreamPushMapper {
@Insert("INSERT INTO wvp_stream_push (app, stream, media_server_id, server_id, push_time, update_time, create_time, pushing) VALUES" + @Insert("INSERT INTO wvp_stream_push (app, stream, media_server_id, server_id, push_time, update_time, create_time, pushing, start_offline_push) VALUES" +
"(#{app}, #{stream}, #{mediaServerId} , #{serverId} , #{pushTime} ,#{updateTime}, #{createTime}, #{pushing})") "(#{app}, #{stream}, #{mediaServerId} , #{serverId} , #{pushTime} ,#{updateTime}, #{createTime}, #{pushing}, #{startOfflinePush})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int add(StreamPush streamPushItem); int add(StreamPush streamPushItem);
@ -28,6 +28,7 @@ public interface StreamPushMapper {
"<if test=\"serverId != null\">, server_id=#{serverId}</if>" + "<if test=\"serverId != null\">, server_id=#{serverId}</if>" +
"<if test=\"pushTime != null\">, push_time=#{pushTime}</if>" + "<if test=\"pushTime != null\">, push_time=#{pushTime}</if>" +
"<if test=\"pushing != null\">, pushing=#{pushing}</if>" + "<if test=\"pushing != null\">, pushing=#{pushing}</if>" +
"<if test=\"startOfflinePush != null\">, start_offline_push=#{startOfflinePush}</if>" +
"WHERE id = #{id}"+ "WHERE id = #{id}"+
" </script>"}) " </script>"})
int update(StreamPush streamPushItem); int update(StreamPush streamPushItem);
@ -61,9 +62,9 @@ public interface StreamPushMapper {
@Insert("<script>" + @Insert("<script>" +
"Insert INTO wvp_stream_push ( " + "Insert INTO wvp_stream_push ( " +
" app, stream, media_server_id, server_id, push_time, update_time, create_time, pushing) " + " app, stream, media_server_id, server_id, push_time, update_time, create_time, pushing, start_offline_push) " +
" VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" + " VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" +
" ( #{item.app}, #{item.stream}, #{item.mediaServerId},#{item.serverId} ,#{item.pushTime}, #{item.updateTime}, #{item.createTime}, #{item.pushing} )" + " ( #{item.app}, #{item.stream}, #{item.mediaServerId},#{item.serverId} ,#{item.pushTime}, #{item.updateTime}, #{item.createTime}, #{item.pushing}, #{item.startOfflinePush} )" +
" </foreach>" + " </foreach>" +
" </script>") " </script>")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
@ -136,4 +137,21 @@ public interface StreamPushMapper {
")</script>") ")</script>")
void batchDel(List<StreamPush> streamPushList); void batchDel(List<StreamPush> streamPushList);
@Update({"<script>" +
"<foreach collection='streamPushItemForUpdate' item='item' separator=';'>" +
" UPDATE" +
" wvp_stream_push" +
" SET update_time=#{item.updateTime}" +
", app=#{item.app}" +
", stream=#{item.stream}" +
", media_server_id=#{item.mediaServerId}" +
", server_id=#{item.serverId}" +
", push_time=#{item.pushTime}" +
", pushing=#{item.pushing}" +
", start_offline_push=#{item.startOfflinePush}" +
" WHERE id=#{item.item.id}" +
"</foreach>" +
"</script>"})
int batchUpdate(List<StreamPush> streamPushItemForUpdate);
} }

View File

@ -90,7 +90,7 @@ public interface IStreamPushService {
void deleteByAppAndStream(String app, String stream); void deleteByAppAndStream(String app, String stream);
void updatePushStatus(Integer streamPushId, boolean pushIng); void updatePushStatus(StreamPush streamPush, boolean pushIng);
void batchUpdate(List<StreamPush> streamPushItemForUpdate); void batchUpdate(List<StreamPush> streamPushItemForUpdate);

View File

@ -4,7 +4,7 @@ import com.baomidou.dynamic.datasource.annotation.DS;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.media.bean.MediaInfo;
import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.service.IMediaServerService;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.ErrorCallback;
@ -53,14 +53,14 @@ public class StreamPushPlayServiceImpl implements IStreamPushPlayService {
public void start(Integer id, ErrorCallback<StreamInfo> callback, String platformDeviceId, String platformName ) { public void start(Integer id, ErrorCallback<StreamInfo> callback, String platformDeviceId, String platformName ) {
StreamPush streamPush = streamPushMapper.queryOne(id); StreamPush streamPush = streamPushMapper.queryOne(id);
Assert.notNull(streamPush, "推流信息未找到"); Assert.notNull(streamPush, "推流信息未找到");
MediaArrivalEvent pushListItem = redisCatchStorage.getPushListItem(streamPush.getApp(), streamPush.getStream()); MediaInfo mediaInfo = redisCatchStorage.getPushListItem(streamPush.getApp(), streamPush.getStream());
if (pushListItem != null) { if (mediaInfo != null) {
String callId = null; String callId = null;
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(streamPush.getApp(), streamPush.getStream()); StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(streamPush.getApp(), streamPush.getStream());
if (streamAuthorityInfo != null) { if (streamAuthorityInfo != null) {
callId = streamAuthorityInfo.getCallId(); callId = streamAuthorityInfo.getCallId();
} }
callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), mediaServerService.getStreamInfoByAppAndStream(pushListItem.getMediaServer(), callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), mediaServerService.getStreamInfoByAppAndStream(mediaInfo.getMediaServer(),
streamPush.getApp(), streamPush.getStream(), null, callId)); streamPush.getApp(), streamPush.getStream(), null, callId));
return; return;
} }
@ -83,7 +83,7 @@ public class StreamPushPlayServiceImpl implements IStreamPushPlayService {
long key = redisRpcService.onStreamOnlineEvent(streamPush.getApp(), streamPush.getStream(), (streamInfo) -> { long key = redisRpcService.onStreamOnlineEvent(streamPush.getApp(), streamPush.getStream(), (streamInfo) -> {
dynamicTask.stop(timeOutTaskKey); dynamicTask.stop(timeOutTaskKey);
if (streamInfo == null) { if (streamInfo == null) {
log.warn("[级联点播] 等待推流得到结果未空: {}/{}", streamPush.getApp(), streamPush.getStream()); log.warn("等待推流得到结果未空: {}/{}", streamPush.getApp(), streamPush.getStream());
callback.run(ErrorCode.ERROR100.getCode(), "fail", null); callback.run(ErrorCode.ERROR100.getCode(), "fail", null);
}else { }else {
callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);

View File

@ -24,7 +24,6 @@ import com.genersoft.iot.vmp.streamPush.service.IStreamPushService;
import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -99,14 +98,11 @@ public class StreamPushServiceImpl implements IStreamPushService {
streamPush.setPushTime(DateUtil.getNow()); streamPush.setPushTime(DateUtil.getNow());
add(streamPush); add(streamPush);
}else { }else {
updatePushStatus(streamPushInDb.getId(), true); updatePushStatus(streamPushInDb, true);
} }
// 冗余数据,自己系统中自用 // 冗余数据,自己系统中自用
if (!"broadcast".equals(event.getApp()) && !"talk".equals(event.getApp())) { if (!"broadcast".equals(event.getApp()) && !"talk".equals(event.getApp())) {
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream( redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event.getMediaInfo());
event.getMediaServer(), event.getApp(), event.getStream(), event.getMediaInfo(), event.getCallId());
event.getHookParam().setStreamInfo(new StreamContent(streamInfo));
redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event);
} }
// 发送流变化redis消息 // 发送流变化redis消息
@ -148,18 +144,12 @@ public class StreamPushServiceImpl implements IStreamPushService {
redisCatchStorage.sendStreamChangeMsg(type, jsonObject); redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
} }
} }
StreamPush push = getPush(event.getApp(), event.getStream()); StreamPush streamPush = getPush(event.getApp(), event.getStream());
if (push == null) { if (streamPush == null) {
return; return;
} }
push.setPushing(false); if (streamPush.getGbDeviceId() != null) {
if (push.getGbDeviceId() != null) { updatePushStatus(streamPush, false);
if (userSetting.isUsePushingAsStatus()) {
push.setGbStatus("OFF");
updateStatus(push);
// streamPushMapper.updatePushStatus(event.getApp(), event.getStream(), false);
// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
}
}else { }else {
deleteByAppAndStream(event.getApp(), event.getStream()); deleteByAppAndStream(event.getApp(), event.getStream());
} }
@ -524,27 +514,28 @@ public class StreamPushServiceImpl implements IStreamPushService {
@Override @Override
public void updateStatus(StreamPush push) { public void updateStatus(StreamPush push) {
if (ObjectUtils.isEmpty(push.getGbDeviceId())) {
return;
}
if ("ON".equalsIgnoreCase(push.getGbStatus())) {
gbChannelService.online(push.buildCommonGBChannel());
}else {
gbChannelService.offline(push.buildCommonGBChannel());
}
} }
@Override @Override
public void updatePushStatus(Integer streamPushId, boolean pushIng) { @Transactional
StreamPush streamPushInDb = streamPushMapper.queryOne(streamPushId); public void updatePushStatus(StreamPush streamPush, boolean pushIng) {
streamPushInDb.setPushing(pushIng); streamPush.setPushing(pushIng);
if (userSetting.isUsePushingAsStatus()) { if (userSetting.isUsePushingAsStatus()) {
streamPushInDb.setGbStatus(pushIng?"ON":"OFF"); streamPush.setGbStatus(pushIng?"ON":"OFF");
}
streamPush.setPushTime(DateUtil.getNow());
streamPushMapper.updatePushStatus(streamPush.getId(), pushIng);
if (ObjectUtils.isEmpty(streamPush.getGbDeviceId())) {
return;
}
if ("ON".equalsIgnoreCase(streamPush.getGbStatus())) {
gbChannelService.online(streamPush.buildCommonGBChannel());
}else {
gbChannelService.offline(streamPush.buildCommonGBChannel());
} }
streamPushInDb.setPushTime(DateUtil.getNow());
updateStatus(streamPushInDb);
} }
private List<StreamPush> handleJSON(List<StreamInfo> streamInfoList) { private List<StreamPush> handleJSON(List<StreamInfo> streamInfoList) {
@ -570,7 +561,16 @@ public class StreamPushServiceImpl implements IStreamPushService {
@Override @Override
public void batchUpdate(List<StreamPush> streamPushItemForUpdate) { public void batchUpdate(List<StreamPush> streamPushItemForUpdate) {
int result = streamPushMapper.batchUpdate(streamPushItemForUpdate);
if (result > 0) {
List<CommonGBChannel> commonGBChannels = new ArrayList<>();
for (StreamPush streamPush : streamPushItemForUpdate) {
if (!ObjectUtils.isEmpty(streamPush.getGbDeviceId())) {
commonGBChannels.add(streamPush.buildCommonGBChannel());
}
}
gbChannelService.batchUpdate(commonGBChannels);
}
} }
@Override @Override

View File

@ -26,7 +26,7 @@
<el-divider content-position="center">策略</el-divider> <el-divider content-position="center">策略</el-divider>
<el-form ref="streamPushForm" status-icon label-width="160px" v-loading="locading"> <el-form ref="streamPushForm" status-icon label-width="160px" v-loading="locading">
<el-form-item style="text-align: left"> <el-form-item style="text-align: left">
<el-checkbox v-model="streamPush.autoPushChannel">线</el-checkbox> <el-checkbox v-model="streamPush.startOfflinePush">线</el-checkbox>
</el-form-item> </el-form-item>
</el-form> </el-form>

View File

@ -52,8 +52,8 @@
</el-table-column> </el-table-column>
<el-table-column label="推流状态" min-width="100"> <el-table-column label="推流状态" min-width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag size="medium" v-if="scope.row.pushIng"></el-tag> <el-tag size="medium" v-if="scope.row.pushing"></el-tag>
<el-tag size="medium" type="info" v-if="!scope.row.pushIng"></el-tag> <el-tag size="medium" type="info" v-if="!scope.row.pushing"></el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="gbDeviceId" label="国标编码" min-width="200" > <el-table-column prop="gbDeviceId" label="国标编码" min-width="200" >

View File

@ -327,7 +327,7 @@ create table wvp_stream_push
update_time character varying(50), update_time character varying(50),
pushing bool default false, pushing bool default false,
self bool default false, self bool default false,
auto_push_channel bool default true, start_offline_push bool default true,
constraint uk_stream_push_app_stream unique (app, stream) constraint uk_stream_push_app_stream unique (app, stream)
); );
create table wvp_cloud_record create table wvp_cloud_record