Compare commits

..

1 Commits

Author SHA1 Message Date
阿斌
1091e359b9
Pre Merge pull request !41 from 阿斌/N/A 2026-04-13 03:44:53 +00:00
46 changed files with 635 additions and 1164 deletions

View File

@ -35,10 +35,16 @@ public class InviteInfo {
private Long createTime; private Long createTime;
private Boolean record;
private String startTime;
private String endTime;
public static InviteInfo getInviteInfo(String deviceId, Integer channelId, String stream, SSRCInfo ssrcInfo, String mediaServerId, public static InviteInfo getInviteInfo(String deviceId, Integer channelId, String stream, SSRCInfo ssrcInfo, String mediaServerId,
String receiveIp, Integer receivePort, String streamMode, String receiveIp, Integer receivePort, String streamMode,
InviteSessionType type, InviteSessionStatus status) { InviteSessionType type, InviteSessionStatus status, Boolean record) {
InviteInfo inviteInfo = new InviteInfo(); InviteInfo inviteInfo = new InviteInfo();
inviteInfo.setDeviceId(deviceId); inviteInfo.setDeviceId(deviceId);
inviteInfo.setChannelId(channelId); inviteInfo.setChannelId(channelId);
@ -50,6 +56,7 @@ public class InviteInfo {
inviteInfo.setType(type); inviteInfo.setType(type);
inviteInfo.setStatus(status); inviteInfo.setStatus(status);
inviteInfo.setMediaServerId(mediaServerId); inviteInfo.setMediaServerId(mediaServerId);
inviteInfo.setRecord(record);
return inviteInfo; return inviteInfo;
} }

View File

@ -53,7 +53,6 @@ public class VideoManagerConstants {
public static final String START_SEND_PUSH_STREAM = "VMP_START_SEND_PUSH_STREAM:"; public static final String START_SEND_PUSH_STREAM = "VMP_START_SEND_PUSH_STREAM:";
public static final String SSE_TASK_KEY = "SSE_TASK_"; public static final String SSE_TASK_KEY = "SSE_TASK_";
public static final String DRAW_THIN_PROCESS_PREFIX = "VMP_DRAW_THIN_PROCESS_"; public static final String DRAW_THIN_PROCESS_PREFIX = "VMP_DRAW_THIN_PROCESS_";
public static final String RTP_AUTHENTICATE = "VMP_RTP_AUTHENTICATE";

View File

@ -15,7 +15,6 @@ public class ChannelDataType {
public final static String PLAYBACK_SERVICE = "sourceChannelPlaybackService"; public final static String PLAYBACK_SERVICE = "sourceChannelPlaybackService";
public final static String DOWNLOAD_SERVICE = "sourceChannelDownloadService"; public final static String DOWNLOAD_SERVICE = "sourceChannelDownloadService";
public final static String PTZ_SERVICE = "sourceChannelPTZService"; public final static String PTZ_SERVICE = "sourceChannelPTZService";
public final static String OTHER_SERVICE = "sourceChannelOtherService";
public static String getDateTypeDesc(Integer dataType) { public static String getDateTypeDesc(Integer dataType) {

View File

@ -0,0 +1,12 @@
package com.genersoft.iot.vmp.common.enums;
public class MediaApp {
public final static String GB28181 = "rtp";
public final static String GB28181_TALK = "talk";
public final static String GB28181_BROADCAST = "broadcast";
public final static String JT1078 = "1078";
public static boolean isKeywords(String app) {
return GB28181.equals(app) || GB28181_TALK.equals(app) || GB28181_BROADCAST.equals(app) || JT1078.equals(app);
}
}

View File

@ -1,76 +0,0 @@
package com.genersoft.iot.vmp.common.enums;
public class MediaStreamUtil {
public final static String LOAD_MP4_APP = "mp4_record";
public final static String RTP_APP = "rtp";
public final static String RTP_STREAM_REST_PREFIX = "s";
public final static String GB28181_TALK = "talk";
public final static String GB28181_BROADCAST = "broadcast";
public final static String JT_TALK = "jt_talk";
public final static String JT1078_STREAM_PREFIX = RTP_STREAM_REST_PREFIX + "_jt";
public final static String JT1078_STREAM_PLAY_PREFIX = RTP_STREAM_REST_PREFIX + "_jt_play";
public final static String JT1078_STREAM_PLAYBACK_PREFIX = RTP_STREAM_REST_PREFIX + "_jt_playback";
public static boolean isKeywords(String app) {
return RTP_APP.equals(app) || GB28181_TALK.equals(app) || GB28181_BROADCAST.equals(app);
}
public static boolean isGB28181(String app, String streamId) {
return RTP_APP.equals(app) && !streamId.startsWith(RTP_STREAM_REST_PREFIX);
}
public static boolean isTalk(String app, String streamId) {
return GB28181_TALK.equals(app);
}
public static boolean isBroadcast(String app, String streamId) {
return GB28181_BROADCAST.equals(app);
}
public static boolean isJT1078(String app, String streamId) {
return RTP_APP.equals(app) && streamId.startsWith(JT1078_STREAM_PREFIX);
}
public static String getJTPlayStreamId(String phoneNumber, int channelId) {
return String.format("%s_%s_%s", JT1078_STREAM_PLAY_PREFIX, phoneNumber, channelId);
}
public static boolean isJT1078Play(String app, String stream) {
return RTP_APP.equals(app) && stream.startsWith(JT1078_STREAM_PLAY_PREFIX + "_");
}
public static boolean isJT1078Playback(String app, String stream) {
return RTP_APP.equals(app) && stream.startsWith(JT1078_STREAM_PLAYBACK_PREFIX + "_");
}
public static boolean isJT1078Talk(String app, String stream) {
return JT_TALK.equals(app);
}
public static String getJTPlaybackStreamId(String phoneNumber, Integer channelId, String startTime, String endTime) {
return String.format("%s_%s_%s_%s_%s", JT1078_STREAM_PLAYBACK_PREFIX, phoneNumber, channelId, startTime, endTime);
}
public static String getJTTalkStreamId(String phoneNumber, Integer channelId) {
return String.format("%s_%s_%s", JT_TALK, phoneNumber, channelId);
}
public static String getJTTalkReceiveStreamId(String phoneNumber, Integer channelId) {
return getJTTalkStreamId(phoneNumber, channelId) + "_receive";
}
public static String[] getJT1078StreamInfo(String app, String stream) {
if (!isJT1078(app, stream)) {
return null;
}
String[] streamInfoArray = stream.split("_");
if (streamInfoArray.length > 5) {
return new String[]{streamInfoArray[3], streamInfoArray[4], streamInfoArray[5], streamInfoArray[6]};
}else {
return new String[]{streamInfoArray[3], streamInfoArray[4]};
}
}
}

View File

@ -106,6 +106,7 @@ public class JwtUtils implements InitializingBean {
if (jwkFile == null || jwkFile.trim().isEmpty()) { if (jwkFile == null || jwkFile.trim().isEmpty()) {
log.warn("[API AUTH] JWK文件路径未配置使用默认配置路径./config/jwk.json"); log.warn("[API AUTH] JWK文件路径未配置使用默认配置路径./config/jwk.json");
jwkFile = "config" + File.separator + "jwk.json"; // 默认外部路径 jwkFile = "config" + File.separator + "jwk.json"; // 默认外部路径
return createAndPersistDefaultRsaKey(jwkFile);
} }
// 尝试读取JWK文件自动处理classpath/本地文件用try-with-resources自动关流无泄露 // 尝试读取JWK文件自动处理classpath/本地文件用try-with-resources自动关流无泄露

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.gb28181.bean; package com.genersoft.iot.vmp.gb28181.bean;
import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.common.enums.ChannelDataType;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
import lombok.Data; import lombok.Data;
@ -205,7 +205,7 @@ public class SendRtpInfo {
sendRtpItem.setChannelId(channelId); sendRtpItem.setChannelId(channelId);
sendRtpItem.setTcp(isTcp); sendRtpItem.setTcp(isTcp);
sendRtpItem.setRtcp(rtcp); sendRtpItem.setRtcp(rtcp);
sendRtpItem.setApp(MediaStreamUtil.RTP_APP); sendRtpItem.setApp(MediaApp.GB28181);
sendRtpItem.setLocalPort(localPort); sendRtpItem.setLocalPort(localPort);
sendRtpItem.setServerId(serverId); sendRtpItem.setServerId(serverId);
sendRtpItem.setMediaServerId(mediaServer.getId()); sendRtpItem.setMediaServerId(mediaServer.getId());

View File

@ -0,0 +1,19 @@
package com.genersoft.iot.vmp.gb28181.bean;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import lombok.Data;
@Data
public class SipSendFailEvent extends SipSubscribe.EventResult<String> {
private String callId;
private String msg;
public static SipSendFailEvent getInstance(String callId, String msg){
SipSendFailEvent sipSendFailEvent = new SipSendFailEvent();
sipSendFailEvent.setMsg(msg);
sipSendFailEvent.setCallId(callId);
return sipSendFailEvent;
}
}

View File

@ -73,7 +73,9 @@ public class DeviceControl {
@Parameter(name = "guardCmd", description = "命令, 可选值SetGuard布防ResetGuard撤防", required = true) @Parameter(name = "guardCmd", description = "命令, 可选值SetGuard布防ResetGuard撤防", required = true)
@GetMapping("/guard") @GetMapping("/guard")
public DeferredResult<WVPResult<String>> guardApi(String deviceId, String guardCmd) { public DeferredResult<WVPResult<String>> guardApi(String deviceId, String guardCmd) {
log.info("[布防/撤防] API调用, deviceId: {}, guardCmd: {}", deviceId, guardCmd); if (log.isDebugEnabled()) {
log.debug("布防/撤防API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId); Device device = deviceService.getDeviceByDeviceId(deviceId);
Assert.notNull(device, "设备不存在"); Assert.notNull(device, "设备不存在");
DeferredResult<WVPResult<String>> result = new DeferredResult<>(); DeferredResult<WVPResult<String>> result = new DeferredResult<>();
@ -107,7 +109,9 @@ public class DeviceControl {
public DeferredResult<WVPResult<String>> resetAlarm(String deviceId, String channelId, public DeferredResult<WVPResult<String>> resetAlarm(String deviceId, String channelId,
@RequestParam(required = false) String alarmMethod, @RequestParam(required = false) String alarmMethod,
@RequestParam(required = false) String alarmType) { @RequestParam(required = false) String alarmType) {
log.info("[报警复位] deviceId: {}, channelId: {}, alarmMethod: {}, alarmType: {}", deviceId, channelId, alarmMethod, alarmType); if (log.isDebugEnabled()) {
log.debug("报警复位API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId); Device device = deviceService.getDeviceByDeviceId(deviceId);
Assert.notNull(device, "设备不存在"); Assert.notNull(device, "设备不存在");
DeferredResult<WVPResult<String>> result = new DeferredResult<>(); DeferredResult<WVPResult<String>> result = new DeferredResult<>();

View File

@ -67,7 +67,9 @@ public class GBRecordController {
@GetMapping("/query/{deviceId}/{channelId}") @GetMapping("/query/{deviceId}/{channelId}")
public DeferredResult<WVPResult<RecordInfo>> recordinfo(@PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime){ public DeferredResult<WVPResult<RecordInfo>> recordinfo(@PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime){
if (log.isDebugEnabled()) {
log.debug(String.format("录像信息查询 API调用deviceId%s startTime%s endTime%s",deviceId, startTime, endTime));
}
DeferredResult<WVPResult<RecordInfo>> result = new DeferredResult<>(Long.valueOf(userSetting.getRecordInfoTimeout()), TimeUnit.MILLISECONDS); DeferredResult<WVPResult<RecordInfo>> result = new DeferredResult<>(Long.valueOf(userSetting.getRecordInfoTimeout()), TimeUnit.MILLISECONDS);
if (!DateUtil.verification(startTime, DateUtil.formatter)){ if (!DateUtil.verification(startTime, DateUtil.formatter)){
throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime格式为" + DateUtil.PATTERN); throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime格式为" + DateUtil.PATTERN);
@ -111,7 +113,9 @@ public class GBRecordController {
public DeferredResult<WVPResult<StreamContent>> download(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId, public DeferredResult<WVPResult<StreamContent>> download(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
String startTime, String endTime, String downloadSpeed) { String startTime, String endTime, String downloadSpeed) {
log.info("[开始历史媒体下载] deviceId: {}, channelId: {}, startTime: {}, endTime: {}, downloadSpeed: {}", deviceId, channelId, startTime, endTime, downloadSpeed); if (log.isDebugEnabled()) {
log.debug(String.format("历史媒体下载 API调用deviceId%schannelId%sdownloadSpeed%s", deviceId, channelId, downloadSpeed));
}
String uuid = UUID.randomUUID().toString(); String uuid = UUID.randomUUID().toString();
String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId; String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;

View File

@ -80,7 +80,9 @@ public class PlaybackController {
public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId, public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
String startTime, String endTime) { String startTime, String endTime) {
log.info("[录像回放] deviceId: {}, channelId: {}, startTime: {}, endTime: {}", deviceId, channelId, startTime, endTime); if (log.isDebugEnabled()) {
log.debug(String.format("设备回放 API调用deviceId%s channelId%s", deviceId, channelId));
}
String uuid = UUID.randomUUID().toString(); String uuid = UUID.randomUUID().toString();
String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId; String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;

View File

@ -1,10 +0,0 @@
package com.genersoft.iot.vmp.gb28181.service;
/**
* 资源能力接入-其他
*/
public interface ISourceOtherService {
Boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema);
}

View File

@ -609,7 +609,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
@Override @Override
public void queryRecordInfo(Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> callback) { public void queryRecordInfo(Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> callback) {
log.info("录像查询 API调用deviceId{}channelId{}startTime{}endTime{}", device.getDeviceId(), channel.getDeviceId(), startTime, endTime);
if (!userSetting.getServerId().equals(device.getServerId())){ if (!userSetting.getServerId().equals(device.getServerId())){
redisRpcPlayService.queryRecordInfo(device.getServerId(), channel.getId(), startTime, endTime, callback); redisRpcPlayService.queryRecordInfo(device.getServerId(), channel.getId(), startTime, endTime, callback);
return; return;

View File

@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.service.impl;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.genersoft.iot.vmp.common.*; import com.genersoft.iot.vmp.common.*;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.dao.DeviceChannelMapper; import com.genersoft.iot.vmp.gb28181.dao.DeviceChannelMapper;
@ -50,7 +50,7 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
@Async @Async
@EventListener @EventListener
public void onApplicationEvent(MediaDepartureEvent event) { public void onApplicationEvent(MediaDepartureEvent event) {
if ("rtsp".equals(event.getSchema()) && MediaStreamUtil.isGB28181(event.getApp(), event.getStream())) { if ("rtsp".equals(event.getSchema()) && MediaApp.GB28181.equals(event.getApp())) {
InviteInfo inviteInfo = getInviteInfoByStream(null, event.getStream()); InviteInfo inviteInfo = getInviteInfoByStream(null, event.getStream());
if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) { if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) {
removeInviteInfo(inviteInfo); removeInviteInfo(inviteInfo);

View File

@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.gb28181.service.impl; package com.genersoft.iot.vmp.gb28181.service.impl;
import com.genersoft.iot.vmp.common.*; import com.genersoft.iot.vmp.common.*;
import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
@ -54,6 +55,7 @@ import javax.sip.ResponseEvent;
import javax.sip.SipException; import javax.sip.SipException;
import java.text.ParseException; import java.text.ParseException;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -607,7 +609,24 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
} }
} }
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForBroadcast(mediaServerItem, platform, channel, ((code, msg, data) -> { String streamId = null;
if (mediaServerItem.isRtpEnable()) {
streamId = String.format("%s_%s", platform.getServerGBId(), channel.getGbDeviceId());
}
// 默认不进行SSRC校验 TODO 后续可改为配置
boolean ssrcCheck = false;
int tcpMode;
if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-PASSIVE")) {
tcpMode = 1;
}else if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) {
tcpMode = 2;
} else {
tcpMode = 0;
}
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServerItem, streamId, null, tcpMode,
false, ssrcCheck, true, false, ((code, msg, data) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && data != null && data.getHookData() != null) { if (code == InviteErrorCode.SUCCESS.getCode() && data != null && data.getHookData() != null) {
log.info("[国标级联] 发起语音喊话 收到上级推流 deviceId: {}, channelId: {}", platform.getServerGBId(), channel.getGbDeviceId()); log.info("[国标级联] 发起语音喊话 收到上级推流 deviceId: {}, channelId: {}", platform.getServerGBId(), channel.getGbDeviceId());
HookData hookData = data.getHookData(); HookData hookData = data.getHookData();
@ -645,15 +664,15 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
return; return;
} }
log.info("[国标级联] 语音喊话发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验{}", log.info("[国标级联] 语音喊话发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验{}",
platform.getServerGBId(), channel.getGbDeviceId(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), false); platform.getServerGBId(), channel.getGbDeviceId(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), ssrcCheck);
// 初始化redis中的invite消息状态 // 初始化redis中的invite消息状态
InviteInfo inviteInfo = InviteInfo.getInviteInfo(platform.getServerGBId(), channel.getGbId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(), InviteInfo inviteInfo = InviteInfo.getInviteInfo(platform.getServerGBId(), channel.getGbId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(),
mediaServerItem.getSdpIp(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), InviteSessionType.BROADCAST, mediaServerItem.getSdpIp(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), InviteSessionType.BROADCAST,
InviteSessionStatus.ready); InviteSessionStatus.ready, userSetting.getRecordSip());
inviteStreamService.updateInviteInfo(inviteInfo); inviteStreamService.updateInviteInfo(inviteInfo);
commanderForPlatform.broadcastInviteCmd(platform, channel,sourceId, mediaServerItem, ssrcInfo, event -> { commanderForPlatform.broadcastInviteCmd(platform, channel,sourceId, mediaServerItem, ssrcInfo, event -> {
inviteOKHandler(event, ssrcInfo, false, mediaServerItem, platform, channel, inviteOKHandler(event, ssrcInfo, tcpMode, ssrcCheck, mediaServerItem, platform, channel,
null, inviteInfo, InviteSessionType.BROADCAST); null, inviteInfo, InviteSessionType.BROADCAST);
}, eventResult -> { }, eventResult -> {
// 收到错误回复 // 收到错误回复
@ -675,7 +694,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
} }
} }
private void inviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, boolean ssrcCheck, MediaServer mediaServerItem, private void inviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, int tcpMode, boolean ssrcCheck, MediaServer mediaServerItem,
Platform platform, CommonGBChannel channel, ErrorCallback<Object> callback, Platform platform, CommonGBChannel channel, ErrorCallback<Object> callback,
InviteInfo inviteInfo, InviteSessionType inviteSessionType){ InviteInfo inviteInfo, InviteSessionType inviteSessionType){
inviteInfo.setStatus(InviteSessionStatus.ok); inviteInfo.setStatus(InviteSessionStatus.ok);
@ -687,11 +706,16 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
ssrcInResponse = ssrcInfo.getSsrc(); ssrcInResponse = ssrcInfo.getSsrc();
} }
if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) { // ssrc 一致
if (mediaServerItem.isRtpEnable()) { if (mediaServerItem.isRtpEnable()) {
tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck, // 多端口
if (tcpMode == 2) {
tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck,
ssrcInfo, callback); ssrcInfo, callback);
}else { }
}else {
// 单端口
if (tcpMode == 2) {
log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流"); log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
} }
} }
@ -729,9 +753,9 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null); updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null);
inviteInfo.setSsrcInfo(ssrcInfo); inviteInfo.setSsrcInfo(ssrcInfo);
inviteInfo.setStream(ssrcInfo.getStream()); inviteInfo.setStream(ssrcInfo.getStream());
if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) { if (tcpMode == 2) {
if (mediaServerItem.isRtpEnable()) { if (mediaServerItem.isRtpEnable()) {
tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck, tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck,
ssrcInfo, callback); ssrcInfo, callback);
}else { }else {
log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流"); log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
@ -745,9 +769,9 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null); updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null);
inviteInfo.setSsrcInfo(ssrcInfo); inviteInfo.setSsrcInfo(ssrcInfo);
inviteInfo.setStream(ssrcInfo.getStream()); inviteInfo.setStream(ssrcInfo.getStream());
if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) { if (tcpMode == 2) {
if (mediaServerItem.isRtpEnable()) { if (mediaServerItem.isRtpEnable()) {
tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck, tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck,
ssrcInfo, callback); ssrcInfo, callback);
}else { }else {
log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流"); log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
@ -803,8 +827,12 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
private void tcpActiveHandler(Platform platform, CommonGBChannel channel, String contentString, private void tcpActiveHandler(Platform platform, CommonGBChannel channel, String contentString,
MediaServer mediaServerItem, boolean ssrcCheck, MediaServer mediaServerItem, int tcpMode, boolean ssrcCheck,
SSRCInfo ssrcInfo, ErrorCallback<Object> callback){ SSRCInfo ssrcInfo, ErrorCallback<Object> callback){
if (tcpMode != 2) {
return;
}
String substring; String substring;
if (contentString.indexOf("y=") > 0) { if (contentString.indexOf("y=") > 0) {
substring = contentString.substring(0, contentString.indexOf("y=")); substring = contentString.substring(0, contentString.indexOf("y="));

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.gb28181.service.impl; package com.genersoft.iot.vmp.gb28181.service.impl;
import com.genersoft.iot.vmp.common.*; import com.genersoft.iot.vmp.common.*;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
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.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.exception.ControllerException;
@ -133,7 +133,7 @@ public class PlayServiceImpl implements IPlayService {
@Async @Async
@EventListener @EventListener
public void onApplicationEvent(MediaArrivalEvent event) { public void onApplicationEvent(MediaArrivalEvent event) {
if (MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp()) || MediaStreamUtil.GB28181_TALK.equals(event.getApp())) { if (MediaApp.GB28181_BROADCAST.equals(event.getApp()) || MediaApp.GB28181_TALK.equals(event.getApp())) {
if (event.getStream().indexOf("_") > 0) { if (event.getStream().indexOf("_") > 0) {
String[] streamArray = event.getStream().split("_"); String[] streamArray = event.getStream().split("_");
if (streamArray.length == 2) { if (streamArray.length == 2) {
@ -149,7 +149,7 @@ public class PlayServiceImpl implements IPlayService {
log.info("[语音对讲/喊话] 未找到通道:{}", channelId); log.info("[语音对讲/喊话] 未找到通道:{}", channelId);
return; return;
} }
if (MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp())) { if (MediaApp.GB28181_BROADCAST.equals(event.getApp())) {
if (audioBroadcastManager.exit(channel.getId())) { if (audioBroadcastManager.exit(channel.getId())) {
stopAudioBroadcast(device, channel); stopAudioBroadcast(device, channel);
} }
@ -160,7 +160,7 @@ public class PlayServiceImpl implements IPlayService {
} catch (InvalidArgumentException | ParseException | SipException e) { } catch (InvalidArgumentException | ParseException | SipException e) {
log.error("[命令发送失败] 语音对讲: {}", e.getMessage()); log.error("[命令发送失败] 语音对讲: {}", e.getMessage());
} }
}else if (MediaStreamUtil.GB28181_TALK.equals(event.getApp())) { }else if (MediaApp.GB28181_TALK.equals(event.getApp())) {
// 开启语音对讲通道 // 开启语音对讲通道
talkCmd(device, channel, event.getMediaServer(), event.getStream(), (msg) -> log.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId)); talkCmd(device, channel, event.getMediaServer(), event.getStream(), (msg) -> log.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId));
} }
@ -205,7 +205,7 @@ public class PlayServiceImpl implements IPlayService {
} }
} }
if (MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp()) || MediaStreamUtil.GB28181_TALK.equals(event.getApp())) { if (MediaApp.GB28181_BROADCAST.equals(event.getApp()) || MediaApp.GB28181_TALK.equals(event.getApp())) {
if (event.getStream().indexOf("_") > 0) { if (event.getStream().indexOf("_") > 0) {
String[] streamArray = event.getStream().split("_"); String[] streamArray = event.getStream().split("_");
if (streamArray.length == 2) { if (streamArray.length == 2) {
@ -221,14 +221,14 @@ public class PlayServiceImpl implements IPlayService {
log.info("[语音对讲/喊话] 未找到通道:{}", channelId); log.info("[语音对讲/喊话] 未找到通道:{}", channelId);
return; return;
} }
if (MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp())) { if (MediaApp.GB28181_BROADCAST.equals(event.getApp())) {
stopAudioBroadcast(device, channel); stopAudioBroadcast(device, channel);
}else if (MediaStreamUtil.GB28181_TALK.equals(event.getApp())) { }else if (MediaApp.GB28181_TALK.equals(event.getApp())) {
stopTalk(device, channel, false); stopTalk(device, channel, false);
} }
} }
} }
}else if (MediaStreamUtil.isGB28181(event.getApp(), event.getStream())) { }else if (MediaApp.GB28181.equals(event.getApp())) {
// 释放ssrc // 释放ssrc
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, event.getStream()); InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, event.getStream());
if (inviteInfo != null && inviteInfo.getStatus() == InviteSessionStatus.ok if (inviteInfo != null && inviteInfo.getStatus() == InviteSessionStatus.ok
@ -246,7 +246,7 @@ public class PlayServiceImpl implements IPlayService {
@Async @Async
@EventListener @EventListener
public void onApplicationEvent(MediaNotFoundEvent event) { public void onApplicationEvent(MediaNotFoundEvent event) {
if (!MediaStreamUtil.isGB28181(event.getApp(), event.getStream())) { if (!MediaApp.GB28181.equals(event.getApp())) {
return; return;
} }
String[] s = event.getStream().split("_"); String[] s = event.getStream().split("_");
@ -354,7 +354,7 @@ public class PlayServiceImpl implements IPlayService {
return inviteInfoInCatch.getSsrcInfo(); return inviteInfoInCatch.getSsrcInfo();
} }
MediaServer mediaInfo = streamInfo.getMediaServer(); MediaServer mediaInfo = streamInfo.getMediaServer();
Boolean ready = mediaServerService.isStreamReady(mediaInfo, MediaStreamUtil.RTP_APP, streamId); Boolean ready = mediaServerService.isStreamReady(mediaInfo, MediaApp.GB28181, streamId);
if (ready != null && ready) { if (ready != null && ready) {
if(callback != null) { if(callback != null) {
callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
@ -375,10 +375,10 @@ public class PlayServiceImpl implements IPlayService {
} }
String streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId()); String streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId());
int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlay(mediaServer, device, channel, ssrc, SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServer, streamId, ssrc, tcpMode, false,
record != null ? record : userSetting.getRecordSip(), device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> {
(code, msg, result) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) {
// hook 响应 // hook 响应
@ -410,14 +410,14 @@ public class PlayServiceImpl implements IPlayService {
} }
inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null, code, msg, null); inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null, code, msg, null);
inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId()); inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaStreamUtil.RTP_APP, streamId); SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaApp.GB28181, streamId);
if (ssrcTransaction != null) { if (ssrcTransaction != null) {
try { try {
cmder.streamByeCmd(device, channel.getDeviceId(), MediaStreamUtil.RTP_APP, streamId, null, null); cmder.streamByeCmd(device, channel.getDeviceId(),MediaApp.GB28181, streamId, null, null);
} catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
log.error("[点播超时] 发送BYE失败 {}", e.getMessage()); log.error("[点播超时] 发送BYE失败 {}", e.getMessage());
} finally { } finally {
sessionManager.removeByStream(MediaStreamUtil.RTP_APP, streamId); sessionManager.removeByStream(MediaApp.GB28181, streamId);
} }
} }
} }
@ -431,15 +431,20 @@ public class PlayServiceImpl implements IPlayService {
null); null);
return null; return null;
} }
String sdpIp = !ObjectUtils.isEmpty(device.getSdpIp()) ? device.getSdpIp() : mediaServer.getSdpIp(); log.info("[点播开始] 设备编号: {}, 通道编号: {}, 收流端口: {}, 流ID{}, 收流模式:{}, SSRC: {}, SSRC校验{}",
log.info("[点播开始] 设备编号: {}, 通道编号: {}, 收流地址: {}:{}, 流ID{}, 收流模式:{}, SSRC: {}, SSRC校验{}", device.getDeviceId(), channel.getDeviceId(), ssrcInfo.getPort(), ssrcInfo.getStream(), channel.getStreamIdentification(),
device.getDeviceId(), channel.getDeviceId(), sdpIp, ssrcInfo.getPort(), ssrcInfo.getStream(), device.getStreamMode(),
ssrcInfo.getSsrc(), device.isSsrcCheck()); ssrcInfo.getSsrc(), device.isSsrcCheck());
// 初始化redis中的invite消息状态 // 初始化redis中的invite消息状态
InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(), InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(),
mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY, mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY,
InviteSessionStatus.ready); InviteSessionStatus.ready, userSetting.getRecordSip());
if (record != null) {
inviteInfo.setRecord(record);
}else {
inviteInfo.setRecord(userSetting.getRecordSip());
}
inviteStreamService.updateInviteInfo(inviteInfo); inviteStreamService.updateInviteInfo(inviteInfo);
try { try {
@ -488,7 +493,7 @@ public class PlayServiceImpl implements IPlayService {
} }
SendRtpInfo sendRtpInfo; SendRtpInfo sendRtpInfo;
try { try {
sendRtpInfo = sendRtpServerService.createSendRtpInfo(mediaServerItem, null, null, playSsrc, device.getDeviceId(), MediaStreamUtil.GB28181_TALK, stream, sendRtpInfo = sendRtpServerService.createSendRtpInfo(mediaServerItem, null, null, playSsrc, device.getDeviceId(), MediaApp.GB28181_TALK, stream,
channel.getId(), true, false); channel.getId(), true, false);
if (sendRtpInfo == null) { if (sendRtpInfo == null) {
ssrcFactory.releaseSsrc(mediaServerItem.getId(), playSsrc); ssrcFactory.releaseSsrc(mediaServerItem.getId(), playSsrc);
@ -539,9 +544,6 @@ public class PlayServiceImpl implements IPlayService {
return; return;
} }
sendRtpInfo.setPort(localPort); sendRtpInfo.setPort(localPort);
// 增加鉴权信息
receiveRtpServerService.addAuthenticateInfoForGb28181Talk(mediaServerItem, sendRtpInfo.getStream());
}catch (ControllerException e) { }catch (ControllerException e) {
mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpInfo.getSsrcToRelease()); mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpInfo.getSsrcToRelease());
log.info("[语音对讲]失败 deviceId: {}, channelId: {}", device.getDeviceId(), channel.getDeviceId()); log.info("[语音对讲]失败 deviceId: {}, channelId: {}", device.getDeviceId(), channel.getDeviceId());
@ -678,7 +680,7 @@ public class PlayServiceImpl implements IPlayService {
String fileName = deviceId + "_" + channelId + ".jpg"; String fileName = deviceId + "_" + channelId + ".jpg";
// 请求截图 // 请求截图
log.info("[请求截图]: " + fileName); log.info("[请求截图]: " + fileName);
mediaServerService.getSnap(mediaServerItemInuse, MediaStreamUtil.RTP_APP, stream, 15, 1, path, fileName); mediaServerService.getSnap(mediaServerItemInuse, MediaApp.GB28181, stream, 15, 1, path, fileName);
} }
public StreamInfo onPublishHandlerForPlay(MediaServer mediaServerItem, MediaInfo mediaInfo, Device device, DeviceChannel channel) { public StreamInfo onPublishHandlerForPlay(MediaServer mediaServerItem, MediaInfo mediaInfo, Device device, DeviceChannel channel) {
@ -760,9 +762,18 @@ public class PlayServiceImpl implements IPlayService {
Device device, DeviceChannel channel, String startTime, Device device, DeviceChannel channel, String startTime,
String endTime, ErrorCallback<StreamInfo> callback) { String endTime, ErrorCallback<StreamInfo> callback) {
String stream = receiveRtpServerService.getPlaybackStream(device, channel, startTime, endTime); String startTimeStr = startTime.replace("-", "")
.replace(":", "")
.replace(" ", "");
String endTimeTimeStr = endTime.replace("-", "")
.replace(":", "")
.replace(" ", "");
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlayback(mediaServer, device, channel, startTime, endTime, (code, msg, result) -> { String stream = device.getDeviceId() + "_" + channel.getDeviceId() + "_" + startTimeStr + "_" + endTimeTimeStr;
int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServer, stream, null, tcpMode, true,
device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) {
// hook响应 // hook响应
StreamInfo streamInfo = onPublishHandlerForPlayback(result.getHookData().getMediaServer(), result.getHookData().getMediaInfo(), device, channel, startTime, endTime); StreamInfo streamInfo = onPublishHandlerForPlayback(result.getHookData().getMediaServer(), result.getHookData().getMediaInfo(), device, channel, startTime, endTime);
@ -780,14 +791,14 @@ public class PlayServiceImpl implements IPlayService {
} }
inviteStreamService.call(InviteSessionType.PLAYBACK, channel.getId(), null, code, msg, null); inviteStreamService.call(InviteSessionType.PLAYBACK, channel.getId(), null, code, msg, null);
inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, channel.getId()); inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, channel.getId());
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaStreamUtil.RTP_APP, stream); SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaApp.GB28181, stream);
if (ssrcTransaction != null) { if (ssrcTransaction != null) {
try { try {
cmder.streamByeCmd(device, channel.getDeviceId(), MediaStreamUtil.RTP_APP, stream, null, null); cmder.streamByeCmd(device, channel.getDeviceId(),MediaApp.GB28181, stream, null, null);
} catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
log.error("[录像回放] 发送BYE失败 {}", e.getMessage()); log.error("[录像回放] 发送BYE失败 {}", e.getMessage());
} finally { } finally {
sessionManager.removeByStream(MediaStreamUtil.RTP_APP, stream); sessionManager.removeByStream(MediaApp.GB28181, stream);
} }
} }
} }
@ -805,12 +816,12 @@ public class PlayServiceImpl implements IPlayService {
} }
log.info("[录像回放] deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验{}", log.info("[录像回放] deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验{}",
device.getDeviceId(), channel.getDeviceId(), startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(), device.getDeviceId(), channel.getGbDeviceId(), startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(),
ssrcInfo.getSsrc(), device.isSsrcCheck()); ssrcInfo.getSsrc(), device.isSsrcCheck());
// 初始化redis中的invite消息状态 // 初始化redis中的invite消息状态
InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(), InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(),
mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK, mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK,
InviteSessionStatus.ready); InviteSessionStatus.ready, userSetting.getRecordSip());
inviteStreamService.updateInviteInfo(inviteInfo); inviteStreamService.updateInviteInfo(inviteInfo);
try { try {
@ -928,19 +939,19 @@ public class PlayServiceImpl implements IPlayService {
if (ssrcInResponse != null) { if (ssrcInResponse != null) {
// 单端口 // 单端口
// 重新订阅流上线 // 重新订阅流上线
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaStreamUtil.RTP_APP, inviteInfo.getStream()); SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaApp.GB28181, inviteInfo.getStream());
if (ssrcTransaction == null) { if (ssrcTransaction == null) {
return; return;
} }
releaseAllocatedSsrc(mediaServerItem, ssrcInfo); releaseAllocatedSsrc(mediaServerItem, ssrcInfo);
sessionManager.removeByStream(MediaStreamUtil.RTP_APP, inviteInfo.getStream()); sessionManager.removeByStream(MediaApp.GB28181, inviteInfo.getStream());
inviteStreamService.updateInviteInfoForSSRC(inviteInfo, ssrcInResponse); inviteStreamService.updateInviteInfoForSSRC(inviteInfo, ssrcInResponse);
ssrcTransaction.setDeviceId(device.getDeviceId()); ssrcTransaction.setDeviceId(device.getDeviceId());
ssrcTransaction.setChannelId(ssrcTransaction.getChannelId()); ssrcTransaction.setChannelId(ssrcTransaction.getChannelId());
ssrcTransaction.setCallId(ssrcTransaction.getCallId()); ssrcTransaction.setCallId(ssrcTransaction.getCallId());
ssrcTransaction.setSsrc(ssrcInResponse); ssrcTransaction.setSsrc(ssrcInResponse);
ssrcTransaction.setAllocatedSsrc(null); ssrcTransaction.setAllocatedSsrc(null);
ssrcTransaction.setApp(MediaStreamUtil.RTP_APP); ssrcTransaction.setApp(MediaApp.GB28181);
ssrcTransaction.setStream(inviteInfo.getStream()); ssrcTransaction.setStream(inviteInfo.getStream());
ssrcTransaction.setMediaServerId(mediaServerItem.getId()); ssrcTransaction.setMediaServerId(mediaServerItem.getId());
ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo((SIPResponse) responseEvent.getResponse())); ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo((SIPResponse) responseEvent.getResponse()));
@ -998,7 +1009,10 @@ public class PlayServiceImpl implements IPlayService {
return; return;
} }
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForDownload(mediaServer, device, channel, startTime, endTime, (code, msg, result) -> { int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServer, null, null, tcpMode, false,
device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) {
// hook响应 // hook响应
StreamInfo streamInfo = onPublishHandlerForDownload(mediaServer, result.getHookData().getMediaInfo(), device, channel, startTime, endTime); StreamInfo streamInfo = onPublishHandlerForDownload(mediaServer, result.getHookData().getMediaInfo(), device, channel, startTime, endTime);
@ -1049,7 +1063,10 @@ public class PlayServiceImpl implements IPlayService {
// 初始化redis中的invite消息状态 // 初始化redis中的invite消息状态
InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(), InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(),
mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD, mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD,
InviteSessionStatus.ready); InviteSessionStatus.ready, true);
inviteInfo.setStartTime(startTime);
inviteInfo.setEndTime(endTime);
inviteStreamService.updateInviteInfo(inviteInfo); inviteStreamService.updateInviteInfo(inviteInfo);
try { try {
cmder.downloadStreamCmd(mediaServer, ssrcInfo, device, channel, startTime, endTime, downloadSpeed, cmder.downloadStreamCmd(mediaServer, ssrcInfo, device, channel, startTime, endTime, downloadSpeed,
@ -1079,7 +1096,7 @@ public class PlayServiceImpl implements IPlayService {
inviteStreamService.updateInviteInfo(inviteInfoForNew, 60*15L); inviteStreamService.updateInviteInfo(inviteInfoForNew, 60*15L);
} }
}; };
Hook hook = Hook.getInstance(HookType.on_record_mp4, MediaStreamUtil.RTP_APP, ssrcInfo.getStream(), mediaServer.getId()); Hook hook = Hook.getInstance(HookType.on_record_mp4, MediaApp.GB28181, ssrcInfo.getStream(), mediaServer.getId());
// 设置过期时间下载失败时自动处理订阅数据 // 设置过期时间下载失败时自动处理订阅数据
hook.setExpireTime(System.currentTimeMillis() + 24 * 60 * 60 * 1000); hook.setExpireTime(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
subscribe.addSubscribe(hook, hookEventForRecord); subscribe.addSubscribe(hook, hookEventForRecord);
@ -1099,7 +1116,7 @@ public class PlayServiceImpl implements IPlayService {
InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, channel.getId(), stream); InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, channel.getId(), stream);
if (inviteInfo == null) { if (inviteInfo == null) {
String app = MediaStreamUtil.RTP_APP; String app = MediaApp.GB28181;
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream); StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
if (streamAuthorityInfo != null) { if (streamAuthorityInfo != null) {
List<CloudRecordItem> allList = cloudRecordService.getAllList(null, app, stream, null, null, null, streamAuthorityInfo.getCallId(), null); List<CloudRecordItem> allList = cloudRecordService.getAllList(null, app, stream, null, null, null, streamAuthorityInfo.getCallId(), null);
@ -1141,7 +1158,7 @@ public class PlayServiceImpl implements IPlayService {
log.warn("[获取下载进度] 查询录像信息时发现节点不存在"); log.warn("[获取下载进度] 查询录像信息时发现节点不存在");
return null; return null;
} }
String app = MediaStreamUtil.RTP_APP; String app = MediaApp.GB28181;
Long duration = mediaServerService.updateDownloadProcess(mediaServerItem, app, stream); Long duration = mediaServerService.updateDownloadProcess(mediaServerItem, app, stream);
if (duration == null || duration == 0) { if (duration == null || duration == 0) {
inviteInfo.getStreamInfo().setProgress(0); inviteInfo.getStreamInfo().setProgress(0);
@ -1184,7 +1201,7 @@ public class PlayServiceImpl implements IPlayService {
public StreamInfo onPublishHandler(MediaServer mediaServerItem, MediaInfo mediaInfo, Device device, DeviceChannel channel) { public StreamInfo onPublishHandler(MediaServer mediaServerItem, MediaInfo mediaInfo, Device device, DeviceChannel channel) {
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, MediaStreamUtil.RTP_APP, mediaInfo.getStream(), mediaInfo, null); StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, MediaApp.GB28181, mediaInfo.getStream(), mediaInfo, null);
streamInfo.setDeviceId(device.getDeviceId()); streamInfo.setDeviceId(device.getDeviceId());
streamInfo.setChannelId(channel.getId()); streamInfo.setChannelId(channel.getId());
return streamInfo; return streamInfo;
@ -1253,7 +1270,7 @@ public class PlayServiceImpl implements IPlayService {
if (broadcastMode == null) { if (broadcastMode == null) {
broadcastMode = true; broadcastMode = true;
} }
String app = broadcastMode ? MediaStreamUtil.GB28181_BROADCAST : MediaStreamUtil.GB28181_TALK; String app = broadcastMode ? MediaApp.GB28181_BROADCAST : MediaApp.GB28181_TALK;
String stream = device.getDeviceId() + "_" + deviceChannel.getDeviceId(); String stream = device.getDeviceId() + "_" + deviceChannel.getDeviceId();
AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult(); AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult();
audioBroadcastResult.setApp(app); audioBroadcastResult.setApp(app);
@ -1555,7 +1572,7 @@ public class PlayServiceImpl implements IPlayService {
SendRtpInfo sendRtpInfo = sendRtpServerService.queryByChannelId(channel.getId(), device.getDeviceId()); SendRtpInfo sendRtpInfo = sendRtpServerService.queryByChannelId(channel.getId(), device.getDeviceId());
if (sendRtpInfo != null) { if (sendRtpInfo != null) {
MediaServer mediaServer = mediaServerService.getOne(sendRtpInfo.getMediaServerId()); MediaServer mediaServer = mediaServerService.getOne(sendRtpInfo.getMediaServerId());
Boolean streamReady = mediaServerService.isStreamReady(mediaServer, MediaStreamUtil.GB28181_TALK, sendRtpInfo.getReceiveStream()); Boolean streamReady = mediaServerService.isStreamReady(mediaServer, MediaApp.GB28181_TALK, sendRtpInfo.getReceiveStream());
if (streamReady) { if (streamReady) {
log.warn("[语音对讲] 进行中: {}", channel.getDeviceId()); log.warn("[语音对讲] 进行中: {}", channel.getDeviceId());
event.call("语音对讲进行中"); event.call("语音对讲进行中");
@ -1630,7 +1647,7 @@ public class PlayServiceImpl implements IPlayService {
String path = "snap"; String path = "snap";
// 请求截图 // 请求截图
log.info("[请求截图]: " + fileName); log.info("[请求截图]: " + fileName);
mediaServerService.getSnap(mediaServer, MediaStreamUtil.RTP_APP, inviteInfo.getStreamInfo().getStream(), 15, 1, path, fileName); mediaServerService.getSnap(mediaServer, MediaApp.GB28181, inviteInfo.getStreamInfo().getStream(), 15, 1, path, fileName);
File snapFile = new File(path + File.separator + fileName); File snapFile = new File(path + File.separator + fileName);
if (snapFile.exists()) { if (snapFile.exists()) {
errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapFile.getAbsoluteFile()); errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapFile.getAbsoluteFile());
@ -1680,7 +1697,7 @@ public class PlayServiceImpl implements IPlayService {
String path = "snap"; String path = "snap";
// 请求截图 // 请求截图
log.info("[请求截图]: 返回byte数组" ); log.info("[请求截图]: 返回byte数组" );
byte[] snapByteArray = mediaServerService.getSnap(mediaServer, MediaStreamUtil.RTP_APP, inviteInfo.getStreamInfo().getStream(), 15, 1, path, null); byte[] snapByteArray = mediaServerService.getSnap(mediaServer, MediaApp.GB28181, inviteInfo.getStreamInfo().getStream(), 15, 1, path, null);
if (snapByteArray != null) { if (snapByteArray != null) {
errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapByteArray); errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapByteArray);
}else { }else {
@ -1694,7 +1711,7 @@ public class PlayServiceImpl implements IPlayService {
if (code == InviteErrorCode.SUCCESS.getCode()) { if (code == InviteErrorCode.SUCCESS.getCode()) {
InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getGbId()); InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getGbId());
if (inviteInfoForPlay != null && inviteInfoForPlay.getStreamInfo() != null) { if (inviteInfoForPlay != null && inviteInfoForPlay.getStreamInfo() != null) {
byte[] snapByteArray = mediaServerService.getSnap(data.getMediaServer(), MediaStreamUtil.RTP_APP, data.getStream(), 15, 1, null, null); byte[] snapByteArray = mediaServerService.getSnap(data.getMediaServer(), MediaApp.GB28181, data.getStream(), 15, 1, null, null);
errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapByteArray); errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapByteArray);
}else { }else {
errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null); errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null);
@ -1712,7 +1729,6 @@ public class PlayServiceImpl implements IPlayService {
if (!userSetting.getServerId().equals(device.getServerId())) { if (!userSetting.getServerId().equals(device.getServerId())) {
redisRpcPlayService.stop(device.getServerId(), type, channel.getId(), stream); redisRpcPlayService.stop(device.getServerId(), type, channel.getId(), stream);
}else { }else {
log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId());
InviteInfo inviteInfo = inviteStreamService.getInviteInfo(type, channel.getId(), stream); InviteInfo inviteInfo = inviteStreamService.getInviteInfo(type, channel.getId(), stream);
if (inviteInfo == null) { if (inviteInfo == null) {
if (type == InviteSessionType.PLAY) { if (type == InviteSessionType.PLAY) {
@ -1723,8 +1739,8 @@ public class PlayServiceImpl implements IPlayService {
inviteStreamService.removeInviteInfo(inviteInfo); inviteStreamService.removeInviteInfo(inviteInfo);
if (InviteSessionStatus.ok == inviteInfo.getStatus()) { if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
try { try {
log.info("[停止点播/回放/下载] 成功 {}/{}", device.getDeviceId(), channel.getDeviceId()); log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId());
cmder.streamByeCmd(device, channel.getDeviceId(), MediaStreamUtil.RTP_APP, inviteInfo.getStream(), null, null); cmder.streamByeCmd(device, channel.getDeviceId(), MediaApp.GB28181, inviteInfo.getStream(), null, null);
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
log.error("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage()); log.error("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
@ -1735,7 +1751,7 @@ public class PlayServiceImpl implements IPlayService {
deviceChannelService.stopPlay(channel.getId()); deviceChannelService.stopPlay(channel.getId());
} }
if (inviteInfo.getStreamInfo() != null) { if (inviteInfo.getStreamInfo() != null) {
receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), MediaStreamUtil.RTP_APP, stream); receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), MediaApp.GB28181, stream);
} }
} }
} }
@ -1757,7 +1773,7 @@ public class PlayServiceImpl implements IPlayService {
if (InviteSessionStatus.ok == inviteInfo.getStatus()) { if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
try { try {
log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId()); log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId());
cmder.streamByeCmd(device, channel.getDeviceId(), MediaStreamUtil.RTP_APP, inviteInfo.getStream(), null, null); cmder.streamByeCmd(device, channel.getDeviceId(), MediaApp.GB28181, inviteInfo.getStream(), null, null);
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
log.warn("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage()); log.warn("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage());
} }
@ -1767,7 +1783,7 @@ public class PlayServiceImpl implements IPlayService {
deviceChannelService.stopPlay(channel.getId()); deviceChannelService.stopPlay(channel.getId());
} }
if (inviteInfo.getStreamInfo() != null) { if (inviteInfo.getStreamInfo() != null) {
receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), MediaStreamUtil.RTP_APP, inviteInfo.getStream()); receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), MediaApp.GB28181, inviteInfo.getStream());
} }
} }

View File

@ -1,55 +0,0 @@
package com.genersoft.iot.vmp.gb28181.service.impl;
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.enums.ChannelDataType;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService;
import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService;
import com.genersoft.iot.vmp.gb28181.service.ISourceOtherService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service(ChannelDataType.OTHER_SERVICE + ChannelDataType.GB28181)
@RequiredArgsConstructor
public class SourceOtherServiceForGbImpl implements ISourceOtherService {
private final IInviteStreamService inviteStreamService;
private final IDeviceChannelService deviceChannelService;
private final UserSetting userSetting;
@Override
public Boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema) {
if (MediaStreamUtil.GB28181_TALK.equals(app) || MediaStreamUtil.GB28181_BROADCAST.equals(app)) {
// 国标对讲/广播流 直接关闭
return false;
}
if (!MediaStreamUtil.isGB28181(app, stream)) {
return null;
}
// 国标流 点播/录像回放/录像下载
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, stream);
if (inviteInfo == null) {
return null;
}
if (inviteInfo.getStatus() == InviteSessionStatus.ok) {
// 录像下载
if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {
return false;
}
DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(inviteInfo.getChannelId());
if (deviceChannel == null) {
return false;
}
}
return userSetting.getStreamOnDemand();
}
}

View File

@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.conf.SipConfig; 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.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
@ -215,8 +215,12 @@ public class SIPCommander implements ISIPCommander {
if (device == null) { if (device == null) {
return; return;
} }
String sdpIp = !ObjectUtils.isEmpty(device.getSdpIp()) ? device.getSdpIp() : mediaServerItem.getSdpIp(); String sdpIp;
if (!ObjectUtils.isEmpty(device.getSdpIp())) {
sdpIp = device.getSdpIp();
}else {
sdpIp = mediaServerItem.getSdpIp();
}
StringBuffer content = new StringBuffer(200); StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n"); content.append("v=0\r\n");
content.append("o=" + device.getDeviceId() + " 0 0 IN IP4 " + sdpIp + "\r\n"); content.append("o=" + device.getDeviceId() + " 0 0 IN IP4 " + sdpIp + "\r\n");
@ -505,7 +509,7 @@ public class SIPCommander implements ISIPCommander {
} }
log.info("[语音喊话] {} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.getPort()); log.info("[语音喊话] {} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.getPort());
Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaStreamUtil.RTP_APP, stream, mediaServerItem.getId()); Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaApp.GB28181, stream, mediaServerItem.getId());
subscribe.addSubscribe(hook, (hookData) -> { subscribe.addSubscribe(hook, (hookData) -> {
if (event != null) { if (event != null) {
event.response(hookData); event.response(hookData);
@ -515,7 +519,7 @@ public class SIPCommander implements ISIPCommander {
CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
callIdHeader.setCallId(callId); callIdHeader.setCallId(callId);
Hook publishHook = Hook.getInstance(HookType.on_publish, MediaStreamUtil.RTP_APP, stream, mediaServerItem.getId()); Hook publishHook = Hook.getInstance(HookType.on_publish, MediaApp.GB28181, stream, mediaServerItem.getId());
subscribe.addSubscribe(publishHook, (hookData) -> { subscribe.addSubscribe(publishHook, (hookData) -> {
if (eventForPush != null) { if (eventForPush != null) {
eventForPush.response(hookData); eventForPush.response(hookData);
@ -549,7 +553,7 @@ public class SIPCommander implements ISIPCommander {
// 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
ResponseEvent responseEvent = (ResponseEvent) e.event; ResponseEvent responseEvent = (ResponseEvent) e.event;
SIPResponse response = (SIPResponse) responseEvent.getResponse(); SIPResponse response = (SIPResponse) responseEvent.getResponse();
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(), MediaStreamUtil.GB28181_TALK,sendRtpItem.getApp(), stream, sendRtpItem.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.TALK); SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(), MediaApp.GB28181_TALK,sendRtpItem.getApp(), stream, sendRtpItem.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.TALK);
ssrcTransaction.setAllocatedSsrc(sendRtpItem.getAllocatedSsrc()); ssrcTransaction.setAllocatedSsrc(sendRtpItem.getAllocatedSsrc());
sessionManager.put(ssrcTransaction); sessionManager.put(ssrcTransaction);
okEvent.response(e); okEvent.response(e);
@ -1392,7 +1396,7 @@ public class SIPCommander implements ISIPCommander {
@Override @Override
public void playbackControlCmd(Device device, DeviceChannel channel, String stream, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { public void playbackControlCmd(Device device, DeviceChannel channel, String stream, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException {
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaStreamUtil.RTP_APP, stream); SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaApp.GB28181, stream);
if (ssrcTransaction == null) { if (ssrcTransaction == null) {
log.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), stream); log.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), stream);
return; return;

View File

@ -695,7 +695,7 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
} }
@Override @Override
public void broadcastInviteCmd(Platform platform, CommonGBChannel channel,String sourceId, MediaServer mediaServer, public void broadcastInviteCmd(Platform platform, CommonGBChannel channel,String sourceId, MediaServer mediaServerItem,
SSRCInfo ssrcInfo, SipSubscribe.Event okEvent, SSRCInfo ssrcInfo, SipSubscribe.Event okEvent,
SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException { SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException {
String stream = ssrcInfo.getStream(); String stream = ssrcInfo.getStream();
@ -704,8 +704,8 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
return; return;
} }
log.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServer.getId(), mediaServer.getIp(), ssrcInfo.getPort()); log.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
String sdpIp = mediaServer.getSdpIp(); String sdpIp = mediaServerItem.getSdpIp();
StringBuffer content = new StringBuffer(200); StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n"); content.append("v=0\r\n");
@ -744,13 +744,13 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
callIdHeader); callIdHeader);
sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> { sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> {
sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream());
mediaServerService.releaseSsrc(mediaServer.getId(), ssrcInfo.getSsrcToRelease()); mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrcToRelease());
errorEvent.response(e); errorEvent.response(e);
}), e -> { }), e -> {
ResponseEvent responseEvent = (ResponseEvent) e.event; ResponseEvent responseEvent = (ResponseEvent) e.event;
SIPResponse response = (SIPResponse) responseEvent.getResponse(); SIPResponse response = (SIPResponse) responseEvent.getResponse();
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForPlatform(platform.getServerGBId(), channel.getGbId(), SsrcTransaction ssrcTransaction = SsrcTransaction.buildForPlatform(platform.getServerGBId(), channel.getGbId(),
callIdHeader.getCallId(), ssrcInfo.getApp(), stream, ssrcInfo.getSsrc(), mediaServer.getId(), response, InviteSessionType.BROADCAST); callIdHeader.getCallId(), ssrcInfo.getApp(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.BROADCAST);
ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc()); ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc());
sessionManager.put(ssrcTransaction); sessionManager.put(ssrcTransaction);
okEvent.response(e); okEvent.response(e);

View File

@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify
import com.genersoft.iot.vmp.common.InviteInfo; import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.service.*; import com.genersoft.iot.vmp.gb28181.service.*;
import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager; import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager;
@ -99,7 +99,7 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
playService.stop(inviteInfo); playService.stop(inviteInfo);
} }
// 去除监听流注销自动停止下载的监听 // 去除监听流注销自动停止下载的监听
Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaStreamUtil.RTP_APP, ssrcTransaction.getStream(), ssrcTransaction.getMediaServerId()); Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaApp.GB28181, ssrcTransaction.getStream(), ssrcTransaction.getMediaServerId());
subscribe.removeSubscribe(hook); subscribe.removeSubscribe(hook);
if (ssrcTransaction.getPlatformId() != null) { if (ssrcTransaction.getPlatformId() != null) {
// 如果级联播放需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题需要将点播CallId进行上下级绑定 // 如果级联播放需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题需要将点播CallId进行上下级绑定

View File

@ -15,6 +15,4 @@ public class JT1078Config {
private Integer port; private Integer port;
private String password; private String password;
private Boolean record = false;
} }

View File

@ -12,6 +12,8 @@ import java.util.List;
public interface Ijt1078PlayService { public interface Ijt1078PlayService {
JTMediaStreamType checkStreamFromJt(String stream);
void play(String phoneNumber, Integer channelId, int type, CommonCallback<WVPResult<StreamInfo>> callback); void play(String phoneNumber, Integer channelId, int type, CommonCallback<WVPResult<StreamInfo>> callback);
void playback(String phoneNumber, Integer channelId, String startTime, String endTime, Integer type, void playback(String phoneNumber, Integer channelId, String startTime, String endTime, Integer type,

View File

@ -1,46 +0,0 @@
package com.genersoft.iot.vmp.jt1078.service.impl;
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.service.ISourceOtherService;
import com.genersoft.iot.vmp.jt1078.service.Ijt1078PlayService;
import com.genersoft.iot.vmp.jt1078.service.Ijt1078Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service(ChannelDataType.OTHER_SERVICE + ChannelDataType.JT_1078)
@RequiredArgsConstructor
public class SourceOtherServiceForJTImpl implements ISourceOtherService {
private final UserSetting userSetting;
private final Ijt1078Service ijt1078Service;
private final Ijt1078PlayService jt1078PlayService;
@Override
public Boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema) {
if (!MediaStreamUtil.isJT1078(app, stream)) {
return null;
}
if (userSetting.getStreamOnDemand()) {
String[] streamParamArray = MediaStreamUtil.getJT1078StreamInfo(app, stream);
if (streamParamArray == null || streamParamArray.length < 2) {
return true;
}
String phoneNumber = streamParamArray[0];
Integer channelId = Integer.parseInt(streamParamArray[1]);
// 判断是否是1078播放类型
if (MediaStreamUtil.isJT1078Play(app, stream)) {
jt1078PlayService.stopPlay(phoneNumber, channelId);
} else if (MediaStreamUtil.isJT1078Playback(app, stream)) {
jt1078PlayService.stopPlayback(phoneNumber, channelId);
}
return true;
}
return false;
}
}

View File

@ -3,14 +3,13 @@ package com.genersoft.iot.vmp.jt1078.service.impl;
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.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
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.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.jt1078.bean.*; import com.genersoft.iot.vmp.jt1078.bean.*;
import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template; import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template;
import com.genersoft.iot.vmp.jt1078.config.JT1078Config;
import com.genersoft.iot.vmp.jt1078.proc.request.J1205; import com.genersoft.iot.vmp.jt1078.proc.request.J1205;
import com.genersoft.iot.vmp.jt1078.proc.response.*; import com.genersoft.iot.vmp.jt1078.proc.response.*;
import com.genersoft.iot.vmp.jt1078.service.Ijt1078PlayService; import com.genersoft.iot.vmp.jt1078.service.Ijt1078PlayService;
@ -31,13 +30,13 @@ import com.genersoft.iot.vmp.service.ISendRtpServerService;
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.RTPServerParam; import com.genersoft.iot.vmp.service.bean.RTPServerParam;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.MediaServerUtils; import com.genersoft.iot.vmp.utils.MediaServerUtils;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
@ -55,6 +54,8 @@ import java.util.concurrent.ConcurrentHashMap;
@Slf4j @Slf4j
public class jt1078PlayServiceImpl implements Ijt1078PlayService { public class jt1078PlayServiceImpl implements Ijt1078PlayService {
public static final String talkApp = "jt_talk";
@Autowired @Autowired
private ISendRtpServerService sendRtpServerService; private ISendRtpServerService sendRtpServerService;
@ -82,16 +83,13 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
@Autowired @Autowired
private UserSetting userSetting; private UserSetting userSetting;
@Autowired
private JT1078Config jt1078Config;
/** /**
* 流到来的处理 * 流到来的处理
*/ */
@Async @Async
@EventListener @EventListener
public void onApplicationEvent(MediaArrivalEvent event) { public void onApplicationEvent(MediaArrivalEvent event) {
if (MediaStreamUtil.JT_TALK.equals(event.getApp()) && event.getStream().endsWith("_talk")) { if (event.getApp().equals(talkApp) && event.getStream().endsWith("_talk")) {
// 收到对JT讲的流 // 收到对JT讲的流
if (event.getStream().indexOf("_") <= 0) { if (event.getStream().indexOf("_") <= 0) {
log.info("[JT-对讲流到来] 流格式有误stream应该为jt_[phoneNumber]_[channelId]_talk"); log.info("[JT-对讲流到来] 流格式有误stream应该为jt_[phoneNumber]_[channelId]_talk");
@ -132,7 +130,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
if (!userSetting.getAutoApplyPlay()) { if (!userSetting.getAutoApplyPlay()) {
return; return;
} }
JTMediaStreamType jtMediaStreamType = checkStreamFromJt(event.getApp(), event.getStream()); JTMediaStreamType jtMediaStreamType = checkStreamFromJt(event.getStream());
if (jtMediaStreamType == null){ if (jtMediaStreamType == null){
return; return;
} }
@ -166,15 +164,17 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
/** /**
* 校验流是否是属于部标的 * 校验流是否是属于部标的
*/ */
private JTMediaStreamType checkStreamFromJt(String app, String stream) { @Override
if (!MediaStreamUtil.isJT1078(app, stream)) { public JTMediaStreamType checkStreamFromJt(String stream) {
if (!stream.startsWith("jt_")) {
return null; return null;
} }
if (MediaStreamUtil.isJT1078Play(app, stream)) { String[] streamParamArray = stream.split("_");
if (streamParamArray.length == 3) {
return JTMediaStreamType.PLAY; return JTMediaStreamType.PLAY;
}else if (MediaStreamUtil.isJT1078Playback(app, stream)) { }else if (streamParamArray.length == 5) {
return JTMediaStreamType.PLAYBACK; return JTMediaStreamType.PLAYBACK;
}else if (MediaStreamUtil.isJT1078Talk(app, stream)) { }else if (streamParamArray.length == 4) {
return JTMediaStreamType.TALK; return JTMediaStreamType.TALK;
}else { }else {
return null; return null;
@ -200,7 +200,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
private void play(JTDevice device, JTChannel channel, int type, CommonCallback<WVPResult<StreamInfo>> callback) { private void play(JTDevice device, JTChannel channel, int type, CommonCallback<WVPResult<StreamInfo>> callback) {
String phoneNumber = device.getPhoneNumber(); String phoneNumber = device.getPhoneNumber();
int channelId = channel.getChannelId(); int channelId = channel.getChannelId();
String finalStream = MediaStreamUtil.getJTPlayStreamId(phoneNumber, channelId); String stream = phoneNumber + "_" + channelId;
// 检查流是否已经存在存在则返回 // 检查流是否已经存在存在则返回
String playKey = VideoManagerConstants.INVITE_INFO_1078_PLAY + phoneNumber + ":" + channelId; String playKey = VideoManagerConstants.INVITE_INFO_1078_PLAY + phoneNumber + ":" + channelId;
List<CommonCallback<WVPResult<StreamInfo>>> errorCallbacks = inviteErrorCallbackMap.computeIfAbsent(playKey, k -> new ArrayList<>()); List<CommonCallback<WVPResult<StreamInfo>>> errorCallbacks = inviteErrorCallbackMap.computeIfAbsent(playKey, k -> new ArrayList<>());
@ -210,7 +210,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
MediaServer mediaServer = streamInfo.getMediaServer(); MediaServer mediaServer = streamInfo.getMediaServer();
if (mediaServer != null) { if (mediaServer != null) {
// 查询流是否存在不存在则删除缓存数据 // 查询流是否存在不存在则删除缓存数据
MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, MediaStreamUtil.RTP_APP, streamInfo.getStream()); MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, MediaApp.JT1078, streamInfo.getStream());
if (mediaInfo != null) { if (mediaInfo != null) {
log.info("[JT-点播] 点播已经存在,直接返回, phoneNumber {} channelId {}", phoneNumber, channelId); log.info("[JT-点播] 点播已经存在,直接返回, phoneNumber {} channelId {}", phoneNumber, channelId);
for (CommonCallback<WVPResult<StreamInfo>> errorCallback : errorCallbacks) { for (CommonCallback<WVPResult<StreamInfo>> errorCallback : errorCallbacks) {
@ -235,29 +235,17 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
} }
return; return;
} }
String streamId;
String streamReplace = null;
if (mediaServer.isRtpEnable()) {
log.info("[JT-点播] 媒体服务器支持rtp开启rtp点播 phoneNumber {} channelId {}", phoneNumber, channelId);
streamId = finalStream;
}else {
String phone = StringUtils.leftPad(device.getPhoneNumber(), 12, '0');
streamId = String.format("%s_%s", phone, channelId);
streamReplace = finalStream;
}
// 开启收流端口 // 开启收流端口
RTPServerParam rtpServerParam = new RTPServerParam(); RTPServerParam rtpServerParam = new RTPServerParam();
rtpServerParam.setMediaServer(mediaServer); rtpServerParam.setMediaServer(mediaServer);
rtpServerParam.setApp(MediaStreamUtil.RTP_APP); rtpServerParam.setApp(MediaApp.JT1078);
rtpServerParam.setStreamId(finalStream); rtpServerParam.setStreamId(stream);
rtpServerParam.setPort(0); rtpServerParam.setPort(0);
rtpServerParam.setTcpMode(1); // 1 表示tcp被动 rtpServerParam.setTcpMode(1); // 1 表示tcp被动
rtpServerParam.setOnlyAuto(false); rtpServerParam.setOnlyAuto(false);
rtpServerParam.setDisableAudio(!channel.isHasAudio()); rtpServerParam.setDisableAudio(!channel.isHasAudio());
int port = receiveRtpServerService.openCommonRTPServer(rtpServerParam, (code, msg, hookData) -> { int port = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, hookData) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) { if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) {
// hook响应 // hook响应
@ -276,8 +264,8 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
String path = "snap"; String path = "snap";
String fileName = phoneNumber + "_" + channelId + ".jpg"; String fileName = phoneNumber + "_" + channelId + ".jpg";
// 请求截图 // 请求截图
log.info("[请求截图]: {}", fileName); log.info("[请求截图]: " + fileName);
mediaServerService.getSnap(mediaServer, MediaStreamUtil.RTP_APP, finalStream, 15, 1, path, fileName); mediaServerService.getSnap(mediaServer, MediaApp.JT1078, stream, 15, 1, path, fileName);
}else { }else {
if (callback != null) { if (callback != null) {
callback.run(WVPResult.fail(code, msg)); callback.run(WVPResult.fail(code, msg));
@ -294,8 +282,6 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
stopPlay(phoneNumber, channelId); stopPlay(phoneNumber, channelId);
return; return;
} }
// 补充鉴权参数
receiveRtpServerService.addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), jt1078Config.getRecord(), null);
log.info("[JT-点播] phoneNumber {} channelId {}IP: {}, 端口: {}", phoneNumber, channelId, mediaServer.getSdpIp(), port); log.info("[JT-点播] phoneNumber {} channelId {}IP: {}, 端口: {}", phoneNumber, channelId, mediaServer.getSdpIp(), port);
J9101 j9101 = new J9101(); J9101 j9101 = new J9101();
@ -309,7 +295,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
} }
public StreamInfo onPublishHandler(MediaServer mediaServerItem, HookData hookData, String phoneNumber, Integer channelId) { public StreamInfo onPublishHandler(MediaServer mediaServerItem, HookData hookData, String phoneNumber, Integer channelId) {
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, MediaStreamUtil.RTP_APP, hookData.getStream(), hookData.getMediaInfo(), null); StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, MediaApp.JT1078, hookData.getStream(), hookData.getMediaInfo(), null);
streamInfo.setDeviceId(phoneNumber); streamInfo.setDeviceId(phoneNumber);
streamInfo.setChannelId(channelId); streamInfo.setChannelId(channelId);
return streamInfo; return streamInfo;
@ -452,8 +438,8 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
redisTemplate.delete(playbackKey); redisTemplate.delete(playbackKey);
} }
String app = MediaStreamUtil.RTP_APP; String app = MediaApp.JT1078;
String finalStream = MediaStreamUtil.getJTPlaybackStreamId(phoneNumber, channelId, String stream = String.format("%s_%s_%s_%s", phoneNumber, channelId,
DateUtil.yyyy_MM_dd_HH_mm_ssToUrl(startTime), DateUtil.yyyy_MM_dd_HH_mm_ssToUrl(endTime)); DateUtil.yyyy_MM_dd_HH_mm_ssToUrl(startTime), DateUtil.yyyy_MM_dd_HH_mm_ssToUrl(endTime));
MediaServer mediaServer; MediaServer mediaServer;
if (org.springframework.util.ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) { if (org.springframework.util.ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) {
@ -467,28 +453,18 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
} }
return; return;
} }
String streamId;
String streamReplace = null;
if (mediaServer.isRtpEnable()) {
log.info("[JT-点播] 媒体服务器支持rtp开启rtp点播 phoneNumber {} channelId {}", phoneNumber, channelId);
streamId = finalStream;
}else {
String phone = StringUtils.leftPad(device.getPhoneNumber(), 12, '0');
streamId = String.format("%s_%s", phone, channelId);
streamReplace = finalStream;
}
// 开启收流端口 // 开启收流端口
RTPServerParam rtpServerParam = new RTPServerParam(); RTPServerParam rtpServerParam = new RTPServerParam();
rtpServerParam.setMediaServer(mediaServer); rtpServerParam.setMediaServer(mediaServer);
rtpServerParam.setApp(MediaStreamUtil.RTP_APP); rtpServerParam.setApp(MediaApp.JT1078);
rtpServerParam.setStreamId(finalStream); rtpServerParam.setStreamId(stream);
rtpServerParam.setPort(0); rtpServerParam.setPort(0);
rtpServerParam.setTcpMode(1); // 1 表示tcp被动 rtpServerParam.setTcpMode(1); // 1 表示tcp被动
rtpServerParam.setOnlyAuto(false); rtpServerParam.setOnlyAuto(false);
rtpServerParam.setDisableAudio(!channel.isHasAudio()); rtpServerParam.setDisableAudio(!channel.isHasAudio());
int port = receiveRtpServerService.openCommonRTPServer(rtpServerParam, (code, msg, hookData) -> { int port = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, hookData) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) { if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) {
// hook 响应 // hook 响应
@ -508,14 +484,10 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
errorCallback.run(new WVPResult<>(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(), errorCallback.run(new WVPResult<>(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(),
InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null)); InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null));
} }
receiveRtpServerService.closeRTPServer(mediaServer, app, finalStream); receiveRtpServerService.closeRTPServer(mediaServer, app, stream);
} }
}); });
log.info("[JT-回放] logInfo {} 端口: {}", logInfo, port); log.info("[JT-回放] logInfo {} 端口: {}", logInfo, port);
// 补充鉴权参数
receiveRtpServerService.addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), jt1078Config.getRecord(), null);
J9201 j9201 = new J9201(); J9201 j9201 = new J9201();
j9201.setChannel(channelId); j9201.setChannel(channelId);
j9201.setIp(mediaServer.getSdpIp()); j9201.setIp(mediaServer.getSdpIp());
@ -623,7 +595,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
JTDevice device = jt1078Service.getDevice(phoneNumber); JTDevice device = jt1078Service.getDevice(phoneNumber);
Assert.notNull(device, "部标设备不存在"); Assert.notNull(device, "部标设备不存在");
String stream = MediaStreamUtil.getJTTalkStreamId(phoneNumber, channelId); String stream = "jt_" + phoneNumber + "_" + channelId + "_talk";
MediaServer mediaServer; MediaServer mediaServer;
if (org.springframework.util.ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) { if (org.springframework.util.ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) {
@ -633,9 +605,9 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
} }
// 检查待发送的流是否存在 // 检查待发送的流是否存在
MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, MediaStreamUtil.JT_TALK, stream); MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, talkApp, stream);
Assert.isNull(mediaInfo, "对讲已经存在"); Assert.isNull(mediaInfo, "对讲已经存在");
return mediaServerService.getStreamInfoByAppAndStream(mediaServer, MediaStreamUtil.JT_TALK, stream, null, null, null, false); return mediaServerService.getStreamInfoByAppAndStream(mediaServer, talkApp, stream, null, null, null, false);
} }
private void sendTalk(JTDevice device, Integer channelId, MediaServer mediaServer, String app, String stream) { private void sendTalk(JTDevice device, Integer channelId, MediaServer mediaServer, String app, String stream) {
@ -646,17 +618,17 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
} }
String phoneNumber = device.getPhoneNumber(); String phoneNumber = device.getPhoneNumber();
String receiveStream = MediaStreamUtil.getJTTalkReceiveStreamId(phoneNumber, channelId);
// 开启收流端口, zlm发送1078的rtp流需要将ssrc字段设置为 imei_channel格式 // 开启收流端口, zlm发送1078的rtp流需要将ssrc字段设置为 imei_channel格式
String ssrc = device.getPhoneNumber() + "_" + channelId; String ssrc = device.getPhoneNumber() + "_" + channelId;
SendRtpInfo sendRtpInfo = sendRtpServerService.createSendRtpInfo(mediaServer, null, null, ssrc, phoneNumber, MediaStreamUtil.JT_TALK, stream, channelId, true, false); SendRtpInfo sendRtpInfo = sendRtpServerService.createSendRtpInfo(mediaServer, null, null, ssrc, phoneNumber, talkApp, stream, channelId, true, false);
sendRtpInfo.setTcpActive(true); sendRtpInfo.setTcpActive(true);
sendRtpInfo.setUsePs(false); sendRtpInfo.setUsePs(false);
sendRtpInfo.setOnlyAudio(true); sendRtpInfo.setOnlyAudio(true);
sendRtpInfo.setReceiveStream(receiveStream); sendRtpInfo.setReceiveStream(stream + "_talk");
// 设置hook监听 // 设置hook监听
Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaStreamUtil.RTP_APP, sendRtpInfo.getReceiveStream(), mediaServer.getId()); Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaApp.JT1078, sendRtpInfo.getReceiveStream(), mediaServer.getId());
subscribe.addSubscribe(hook, (hookData) -> { subscribe.addSubscribe(hook, (hookData) -> {
log.info("[JT-对讲] 对讲连接建立, phoneNumber {} channelId {}", phoneNumber, channelId); log.info("[JT-对讲] 对讲连接建立, phoneNumber {} channelId {}", phoneNumber, channelId);
subscribe.removeSubscribe(hook); subscribe.removeSubscribe(hook);

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.media.abl; package com.genersoft.iot.vmp.media.abl;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
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.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.service.IDeviceService;
@ -189,14 +189,14 @@ public class ABLHttpHookListener {
logger.info("[ABL HOOK] 码流不到达通知:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); logger.info("[ABL HOOK] 码流不到达通知:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream());
try { try {
if (MediaStreamUtil.RTP_APP.equals(param.getApp())) { if (MediaApp.GB28181.equals(param.getApp())) {
return HookResult.SUCCESS(); return HookResult.SUCCESS();
} }
MediaRtpServerTimeoutEvent event = new MediaRtpServerTimeoutEvent(this); MediaRtpServerTimeoutEvent event = new MediaRtpServerTimeoutEvent(this);
MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId()); MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
if (mediaServerItem != null) { if (mediaServerItem != null) {
event.setMediaServer(mediaServerItem); event.setMediaServer(mediaServerItem);
event.setApp(MediaStreamUtil.RTP_APP); event.setApp(MediaApp.GB28181);
applicationEventPublisher.publishEvent(event); applicationEventPublisher.publishEvent(event);
} }
}catch (Exception e) { }catch (Exception e) {

View File

@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.common.CommonCallback;
import com.genersoft.iot.vmp.common.InviteInfo; import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.conf.SipConfig; 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;
@ -248,7 +248,7 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService {
streamInfoResult.setMediaInfo(mediaInfo); streamInfoResult.setMediaInfo(mediaInfo);
if (!MediaStreamUtil.GB28181_BROADCAST.equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) { if (!MediaApp.GB28181_BROADCAST.equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) {
String newStream = stream + "_" + mediaServer.getTranscodeSuffix(); String newStream = stream + "_" + mediaServer.getTranscodeSuffix();
mediaServer.setTranscodeSuffix(null); mediaServer.setTranscodeSuffix(null);
StreamInfo transcodeStreamInfo = getStreamInfoByAppAndStream(mediaServer, app, newStream, null, addr, callId, isPlay); StreamInfo transcodeStreamInfo = getStreamInfoByAppAndStream(mediaServer, app, newStream, null, addr, callId, isPlay);

View File

@ -1,16 +1,59 @@
package com.genersoft.iot.vmp.media.bean; package com.genersoft.iot.vmp.media.bean;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ResultForOnPublish { public class ResultForOnPublish {
private Boolean enable_audio; private boolean enable_audio;
private Boolean enable_mp4; private boolean enable_mp4;
private Integer mp4_max_second; private int mp4_max_second;
private String mp4_save_path; private String mp4_save_path;
private String stream_replace; private String stream_replace;
private Integer modify_stamp; private Integer modify_stamp;
public boolean isEnable_audio() {
return enable_audio;
}
public void setEnable_audio(boolean enable_audio) {
this.enable_audio = enable_audio;
}
public boolean isEnable_mp4() {
return enable_mp4;
}
public void setEnable_mp4(boolean enable_mp4) {
this.enable_mp4 = enable_mp4;
}
public int getMp4_max_second() {
return mp4_max_second;
}
public void setMp4_max_second(int mp4_max_second) {
this.mp4_max_second = mp4_max_second;
}
public String getMp4_save_path() {
return mp4_save_path;
}
public void setMp4_save_path(String mp4_save_path) {
this.mp4_save_path = mp4_save_path;
}
public String getStream_replace() {
return stream_replace;
}
public void setStream_replace(String stream_replace) {
this.stream_replace = stream_replace;
}
public Integer getModify_stamp() {
return modify_stamp;
}
public void setModify_stamp(Integer modify_stamp) {
this.modify_stamp = modify_stamp;
}
} }

View File

@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.conf.MediaConfig; import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
@ -263,7 +263,7 @@ public class ZLMHttpHookListener {
log.info("[ZLM HOOK] rtp发送关闭{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream()); log.info("[ZLM HOOK] rtp发送关闭{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream());
// 查找对应的上级推流发送停止 // 查找对应的上级推流发送停止
if (!MediaStreamUtil.RTP_APP.equals(param.getApp())) { if (!MediaApp.GB28181.equals(param.getApp())) {
return HookResult.SUCCESS(); return HookResult.SUCCESS();
} }
try { try {
@ -294,7 +294,7 @@ public class ZLMHttpHookListener {
MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId()); MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
if (mediaServerItem != null) { if (mediaServerItem != null) {
event.setMediaServer(mediaServerItem); event.setMediaServer(mediaServerItem);
event.setApp(MediaStreamUtil.RTP_APP); event.setApp(MediaApp.GB28181);
applicationEventPublisher.publishEvent(event); applicationEventPublisher.publishEvent(event);
} }
}catch (Exception e) { }catch (Exception e) {

View File

@ -5,7 +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.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
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.SendRtpInfo; import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
@ -516,7 +516,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
@Override @Override
public void loadMP4File(MediaServer mediaServer, String app, String stream, String filePath, String fileName, ErrorCallback<StreamInfo> callback) { public void loadMP4File(MediaServer mediaServer, String app, String stream, String filePath, String fileName, ErrorCallback<StreamInfo> callback) {
String buildApp = MediaStreamUtil.LOAD_MP4_APP; String buildApp = "mp4_record";
String buildStream = app + "_" + stream + "_" + fileName + "_" + RandomStringUtils.randomAlphabetic(6).toLowerCase(); String buildStream = app + "_" + stream + "_" + fileName + "_" + RandomStringUtils.randomAlphabetic(6).toLowerCase();
Hook hook = Hook.getInstance(HookType.on_media_arrival, buildApp, buildStream, mediaServer.getServerId()); Hook hook = Hook.getInstance(HookType.on_media_arrival, buildApp, buildStream, mediaServer.getServerId());
@ -539,7 +539,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
@Override @Override
public void loadMP4FileForDate(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback<StreamInfo> callback) { public void loadMP4FileForDate(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback<StreamInfo> callback) {
String buildApp = MediaStreamUtil.LOAD_MP4_APP; String buildApp = "mp4_record";
String buildStream = app + "_" + stream + "_" + date; String buildStream = app + "_" + stream + "_" + date;
MediaInfo mediaInfo = getMediaInfo(mediaServer, buildApp, buildStream); MediaInfo mediaInfo = getMediaInfo(mediaServer, buildApp, buildStream);
if (mediaInfo != null) { if (mediaInfo != null) {
@ -681,7 +681,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
streamInfoResult.setMediaInfo(mediaInfo); streamInfoResult.setMediaInfo(mediaInfo);
if (!MediaStreamUtil.GB28181_BROADCAST.equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) { if (!MediaApp.GB28181_BROADCAST.equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) {
String newStream = stream + "_" + mediaServer.getTranscodeSuffix(); String newStream = stream + "_" + mediaServer.getTranscodeSuffix();
mediaServer.setTranscodeSuffix(null); mediaServer.setTranscodeSuffix(null);
StreamInfo transcodeStreamInfo = getStreamInfoByAppAndStream(mediaServer, app, newStream, null, addr, callId, isPlay); StreamInfo transcodeStreamInfo = getStreamInfoByAppAndStream(mediaServer, app, newStream, null, addr, callId, isPlay);

View File

@ -211,16 +211,6 @@ public class ZLMMediaServerStatusManager {
String key = "zlm-keepalive-" + mediaServer.getId(); String key = "zlm-keepalive-" + mediaServer.getId();
dynamicTask.startDelay(key, ()->{ dynamicTask.startDelay(key, ()->{
log.warn("[ZLM-心跳超时] ID{}", mediaServer.getId()); log.warn("[ZLM-心跳超时] ID{}", mediaServer.getId());
// 主动探测一次避免因短暂网络抖动误判离线
ZLMResult<List<JSONObject>> probeResult = zlmresTfulUtils.getMediaServerConfig(mediaServer);
if (probeResult != null && probeResult.getData() != null && !probeResult.getData().isEmpty()) {
log.info("[ZLM-心跳超时] 主动探测成功,服务仍在线,重置心跳计时器 ID{}", mediaServer.getId());
ZLMServerConfig zlmServerConfig = JSON.parseObject(JSON.toJSONString(probeResult.getData().get(0)), ZLMServerConfig.class);
initPort(mediaServer, zlmServerConfig);
online(mediaServer, zlmServerConfig);
return;
}
log.warn("[ZLM-心跳超时] 主动探测失败,确认离线 ID{}", mediaServer.getId());
mediaServer.setStatus(false); mediaServer.setStatus(false);
offlineZlmPrimaryMap.put(mediaServer.getId(), mediaServer); offlineZlmPrimaryMap.put(mediaServer.getId(), mediaServer);
offlineZlmTimeMap.put(mediaServer.getId(), System.currentTimeMillis()); offlineZlmTimeMap.put(mediaServer.getId(), System.currentTimeMillis());

View File

@ -1,10 +1,5 @@
package com.genersoft.iot.vmp.media.zlm.dto.hook; package com.genersoft.iot.vmp.media.zlm.dto.hook;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class HookResult { public class HookResult {
private int code; private int code;
@ -27,4 +22,19 @@ public class HookResult {
return new HookResultForOnPublish(-1, "fail"); return new HookResultForOnPublish(-1, "fail");
} }
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
} }

View File

@ -8,9 +8,9 @@ import lombok.Setter;
@Getter @Getter
public class HookResultForOnPublish extends HookResult{ public class HookResultForOnPublish extends HookResult{
private Boolean enable_audio; private boolean enable_audio;
private Boolean enable_mp4; private boolean enable_mp4;
private Integer mp4_max_second; private int mp4_max_second;
private String mp4_save_path; private String mp4_save_path;
private String stream_replace; private String stream_replace;
private Integer modify_stamp; private Integer modify_stamp;
@ -24,8 +24,8 @@ public class HookResultForOnPublish extends HookResult{
public static HookResultForOnPublish getInstance(ResultForOnPublish resultForOnPublish){ public static HookResultForOnPublish getInstance(ResultForOnPublish resultForOnPublish){
HookResultForOnPublish successResult = new HookResultForOnPublish(0, "success"); HookResultForOnPublish successResult = new HookResultForOnPublish(0, "success");
successResult.setEnable_audio(resultForOnPublish.getEnable_audio()); successResult.setEnable_audio(resultForOnPublish.isEnable_audio());
successResult.setEnable_mp4(resultForOnPublish.getEnable_mp4()); successResult.setEnable_mp4(resultForOnPublish.isEnable_mp4());
successResult.setModify_stamp(resultForOnPublish.getModify_stamp()); successResult.setModify_stamp(resultForOnPublish.getModify_stamp());
successResult.setStream_replace(resultForOnPublish.getStream_replace()); successResult.setStream_replace(resultForOnPublish.getStream_replace());
successResult.setMp4_max_second(resultForOnPublish.getMp4_max_second()); successResult.setMp4_max_second(resultForOnPublish.getMp4_max_second());

View File

@ -1,8 +1,8 @@
package com.genersoft.iot.vmp.service; package com.genersoft.iot.vmp.service;
import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.OpenRTPServerResult;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
import com.genersoft.iot.vmp.media.event.hook.HookData; import com.genersoft.iot.vmp.media.event.hook.HookData;
import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.RTPServerParam; import com.genersoft.iot.vmp.service.bean.RTPServerParam;
@ -14,29 +14,9 @@ public interface IReceiveRtpServerService {
boolean playback, boolean ssrcCheck, boolean onlyAuto, boolean disableAuto, boolean playback, boolean ssrcCheck, boolean onlyAuto, boolean disableAuto,
ErrorCallback<OpenRTPServerResult> callback); ErrorCallback<OpenRTPServerResult> callback);
SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel, int openRTPServer(RTPServerParam rtpServerParam, ErrorCallback<HookData> callback);
String presetSSRC, boolean record, ErrorCallback<OpenRTPServerResult> callback);
SSRCInfo openGbRTPServerForPlayback(MediaServer mediaServer, Device device, DeviceChannel channel,
String startTime, String endTime, ErrorCallback<OpenRTPServerResult> callback);
SSRCInfo openGbRTPServerForDownload(MediaServer mediaServer, Device device, DeviceChannel channel,
String startTime, String endTime, ErrorCallback<OpenRTPServerResult> callback);
String getPlaybackStream(Device device, DeviceChannel channel, String startTime, String endTime);
SSRCInfo openGbRTPServerForBroadcast(MediaServer mediaServer, Platform platform, CommonGBChannel channel,
ErrorCallback<OpenRTPServerResult> callback);
int openCommonRTPServer(RTPServerParam rtpServerParam, ErrorCallback<HookData> callback);
void closeRTPServer(MediaServer mediaServer, String app, String stream); void closeRTPServer(MediaServer mediaServer, String app, String stream);
void closeRTPServerByMediaServerId(String mediaServerId, String app, String stream); void closeRTPServerByMediaServerId(String mediaServerId, String app, String stream);
void addAuthenticateInfoForGb28181Talk(MediaServer mediaServer, String streamId);
void addAuthenticateInfo(String streamId, String streamReplace, Boolean enableAudio, Boolean enableMp4, Integer mp4MaxSecond);
ResultForOnPublish getAuthenticateInfo(String streamId);
} }

View File

@ -9,13 +9,13 @@ public class SSRCInfo {
private String ssrc; private String ssrc;
private String allocatedSsrc; private String allocatedSsrc;
private String app; private String app;
private String stream; private String Stream;
public SSRCInfo(int port, String ssrc, String app, String stream) { public SSRCInfo(int port, String ssrc, String app, String stream) {
this.port = port; this.port = port;
this.ssrc = ssrc; this.ssrc = ssrc;
this.app = app; this.app = app;
this.stream = stream; this.Stream = stream;
} }
public String getSsrcToRelease() { public String getSsrcToRelease() {

View File

@ -1,53 +1,89 @@
package com.genersoft.iot.vmp.service.impl; package com.genersoft.iot.vmp.service.impl;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; 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.VideoManagerConstants;
import com.genersoft.iot.vmp.common.enums.MediaApp;
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.service.ISourceOtherService; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService;
import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService;
import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager;
import com.genersoft.iot.vmp.jt1078.bean.JTMediaStreamType;
import com.genersoft.iot.vmp.jt1078.service.Ijt1078PlayService;
import com.genersoft.iot.vmp.jt1078.service.Ijt1078Service;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.bean.ResultForOnPublish; import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.IMediaService; import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.service.IReceiveRtpServerService;
import com.genersoft.iot.vmp.service.IRecordPlanService; import com.genersoft.iot.vmp.service.IRecordPlanService;
import com.genersoft.iot.vmp.service.ISendRtpServerService;
import com.genersoft.iot.vmp.service.IUserService; import com.genersoft.iot.vmp.service.IUserService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyService; import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyService;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.MediaServerUtils; import com.genersoft.iot.vmp.utils.MediaServerUtils;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import lombok.RequiredArgsConstructor; import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Map; import java.util.Map;
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor
public class MediaServiceImpl implements IMediaService { public class MediaServiceImpl implements IMediaService {
private final IRedisCatchStorage redisCatchStorage; @Autowired
private IRedisCatchStorage redisCatchStorage;
private final IStreamProxyService streamProxyService; @Autowired
private IStreamProxyService streamProxyService;
private final UserSetting userSetting; @Autowired
private UserSetting userSetting;
private final IUserService userService; @Autowired
private RedisTemplate<Object, Object> redisTemplate;
private final IReceiveRtpServerService receiveRtpServerService; @Autowired
private IUserService userService;
private final IRecordPlanService recordPlanService; @Autowired
private IInviteStreamService inviteStreamService;
private final Map<String, ISourceOtherService> sourceOtherServiceMap; @Autowired
private IDeviceChannelService deviceChannelService;
@Autowired
private SipInviteSessionManager sessionManager;
@Autowired
private Ijt1078Service ijt1078Service;
@Autowired
private Ijt1078PlayService jt1078PlayService;
@Autowired
private ISendRtpServerService sendRtpServerService;
@Autowired
private IRecordPlanService recordPlanService;
@Override @Override
public boolean authenticatePlay(String app, String stream, String callId) { public boolean authenticatePlay(String app, String stream, String callId) {
if (app == null || stream == null) { if (app == null || stream == null) {
return false; return false;
} }
if (MediaStreamUtil.RTP_APP.equals(app)) { if (MediaApp.GB28181.equals(app)) {
return true; return true;
} }
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream); StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
@ -59,24 +95,29 @@ public class MediaServiceImpl implements IMediaService {
@Override @Override
public ResultForOnPublish authenticatePublish(MediaServer mediaServer, String app, String stream, String params) { public ResultForOnPublish authenticatePublish(MediaServer mediaServer, String app, String stream, String params) {
// 推流鉴权的处理
if (MediaStreamUtil.RTP_APP.equals(app)) { if (!MediaApp.GB28181.equals(app) && !MediaApp.JT1078.equals(app) ) {
return receiveRtpServerService.getAuthenticateInfo(stream); if (MediaApp.GB28181_TALK.equals(app) && stream.endsWith("_talk")) {
}else { ResultForOnPublish result = new ResultForOnPublish();
ResultForOnPublish result = new ResultForOnPublish();
// app RTP_APP 的流 如果是国标对讲或者广播则默认获取声音并且不录制 其他的流先查询是否有代理配置如果没有代理配置再进行鉴权
if (MediaStreamUtil.GB28181_TALK.equals(app) || MediaStreamUtil.GB28181_BROADCAST.equals(app) || MediaStreamUtil.JT_TALK.equals(app)) {
result.setEnable_mp4(false); result.setEnable_mp4(false);
result.setEnable_audio(true); result.setEnable_audio(true);
return result; return result;
} }
if (MediaStreamUtil.LOAD_MP4_APP.equals(app) ) { if ("jt_talk".equals(app) && stream.endsWith("_talk")) {
ResultForOnPublish result = new ResultForOnPublish();
result.setEnable_mp4(false);
result.setEnable_audio(true);
return result;
}
if ("mp4_record".equals(app) ) {
ResultForOnPublish result = new ResultForOnPublish();
result.setEnable_mp4(false); result.setEnable_mp4(false);
result.setEnable_audio(true); result.setEnable_audio(true);
return result; return result;
} }
StreamProxy streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, stream); StreamProxy streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, stream);
if (streamProxyItem != null) { if (streamProxyItem != null) {
ResultForOnPublish result = new ResultForOnPublish();
result.setEnable_audio(streamProxyItem.isEnableAudio()); result.setEnable_audio(streamProxyItem.isEnableAudio());
result.setEnable_mp4(streamProxyItem.isEnableMp4()); result.setEnable_mp4(streamProxyItem.isEnableMp4());
return result; return result;
@ -109,46 +150,152 @@ public class MediaServiceImpl implements IMediaService {
// 鉴权通过 // 鉴权通过
redisCatchStorage.updateStreamAuthorityInfo(app, stream, streamAuthorityInfo); redisCatchStorage.updateStreamAuthorityInfo(app, stream, streamAuthorityInfo);
} }
result.setEnable_mp4(userSetting.getRecordPushLive());
return result;
} }
ResultForOnPublish result = new ResultForOnPublish();
result.setEnable_audio(true);
// 国标流
if (MediaApp.GB28181.equals(app)) {
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, stream);
if (inviteInfo != null) {
result.setEnable_mp4(inviteInfo.getRecord());
}else {
result.setEnable_mp4(userSetting.getRecordSip());
}
// 单端口模式下修改流 ID
if (!mediaServer.isRtpEnable() && inviteInfo == null) {
String ssrc = String.format("%010d", Long.parseLong(stream, 16));
inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc);
if (inviteInfo != null) {
result.setStream_replace(inviteInfo.getStream());
log.info("[HOOK]推流鉴权 stream: {} 替换为 {}", stream, inviteInfo.getStream());
stream = inviteInfo.getStream();
}
}
// 设置音频信息及录制信息
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(app, stream);
if (ssrcTransaction != null ) {
// 为录制国标模拟一个鉴权信息, 方便后续写入录像文件时使用
StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(app, stream, mediaServer.getId());
streamAuthorityInfo.setApp(app);
streamAuthorityInfo.setStream(ssrcTransaction.getStream());
streamAuthorityInfo.setCallId(ssrcTransaction.getSipTransactionInfo().getCallId());
redisCatchStorage.updateStreamAuthorityInfo(app, ssrcTransaction.getStream(), streamAuthorityInfo);
String deviceId = ssrcTransaction.getDeviceId();
Integer channelId = ssrcTransaction.getChannelId();
DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channelId);
if (deviceChannel != null) {
result.setEnable_audio(deviceChannel.isHasAudio());
}
// 如果是录像下载就设置视频间隔十秒
if (ssrcTransaction.getType() == InviteSessionType.DOWNLOAD) {
// 获取录像的总时长然后设置为这个视频的时长
InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, channelId, stream);
if (inviteInfoForDownload != null) {
String startTime = inviteInfoForDownload.getStartTime();
String endTime = inviteInfoForDownload.getEndTime();
long difference = DateUtil.getDifference(startTime, endTime) / 1000;
result.setMp4_max_second((int) difference);
result.setEnable_mp4(true);
// 设置为2保证得到的mp4的时长是正常的
result.setModify_stamp(2);
}
}
// 如果是talk对讲则默认获取声音
if (ssrcTransaction.getType() == InviteSessionType.TALK) {
result.setEnable_audio(true);
}
}
} else if (app.equals(MediaApp.GB28181_BROADCAST)) {
result.setEnable_audio(true);
result.setEnable_mp4(userSetting.getRecordSip());
} else if (app.equals(MediaApp.GB28181_TALK)) {
result.setEnable_audio(true);
result.setEnable_mp4(userSetting.getRecordSip());
}else {
result.setEnable_mp4(userSetting.getRecordPushLive());
}
if (app.equalsIgnoreCase(MediaApp.GB28181)) {
String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + stream;
OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo) redisTemplate.opsForValue().get(receiveKey);
String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + stream;
OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo) redisTemplate.opsForValue().get(receiveKeyForPS);
if (otherRtpSendInfo != null || otherPsSendInfo != null) {
result.setEnable_mp4(true);
}
}
return result;
} }
@Override @Override
public boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema) { public boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema) {
boolean result = false;
if (recordPlanService.recording(app, stream) != null) { if (recordPlanService.recording(app, stream) != null) {
return false; return false;
} }
if (MediaStreamUtil.LOAD_MP4_APP.equals(app)) { // 国标类型的流
// mp4点播流 无人观看不关闭 if (MediaApp.GB28181.equals(app)) {
return true; result = userSetting.getStreamOnDemand();
} // 国标流 点播/录像回放/录像下载
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, stream);
for (ISourceOtherService sourceOtherService : sourceOtherServiceMap.values()) { if (inviteInfo != null) {
try { if (inviteInfo.getStatus() == InviteSessionStatus.ok){
Boolean result = sourceOtherService.closeStreamOnNoneReader(mediaServerId, app, stream, schema); // 录像下载
if (result != null) { if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {
return result; return false;
}
DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(inviteInfo.getChannelId());
if (deviceChannel == null) {
return false;
}
} }
}catch (Exception e) { return result;
log.error("调用其他服务关闭无人观看流失败, app={}, stream={}, schema={}", app, stream, schema, e);
} }
} }else if (MediaApp.JT1078.equals(app)) {
// 判断是否是1078播放类型
// 拉流代理 JTMediaStreamType jtMediaStreamType = ijt1078Service.checkStreamFromJt(stream);
StreamProxy streamProxy = streamProxyService.getStreamProxyByAppAndStream(app, stream); if (jtMediaStreamType != null) {
if (streamProxy != null) { String[] streamParamArray = stream.split("_");
if (streamProxy.isEnableDisableNoneReader()) { if (jtMediaStreamType.equals(JTMediaStreamType.PLAY)) {
// 无人观看停用 jt1078PlayService.stopPlay(streamParamArray[0], Integer.parseInt(streamParamArray[1]));
// 修改数据 }else if (jtMediaStreamType.equals(JTMediaStreamType.PLAYBACK)) {
streamProxyService.stopByAppAndStream(app, stream); jt1078PlayService.stopPlayback(streamParamArray[0], Integer.parseInt(streamParamArray[1]));
return true; }
} else { }else {
// 无人观看不做处理
return false; return false;
} }
}else if (MediaApp.GB28181_TALK.equals(app) || MediaApp.GB28181_BROADCAST.equals(app)) {
return false;
} else if ("mp4_record".equals(app)) {
return true;
} else { } else {
return userSetting.getStreamOnDemand(); // 非国标流 推流/拉流代理
// 拉流代理
StreamProxy streamProxy = streamProxyService.getStreamProxyByAppAndStream(app, stream);
if (streamProxy != null) {
if (streamProxy.isEnableDisableNoneReader()) {
// 无人观看停用
// 修改数据
streamProxyService.stopByAppAndStream(app, stream);
return true;
} else {
// 无人观看不做处理
return false;
}
}else {
return false;
}
} }
return result;
} }
} }

View File

@ -1,13 +1,12 @@
package com.genersoft.iot.vmp.service.impl; package com.genersoft.iot.vmp.service.impl;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
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.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.bean.OpenRTPServerResult;
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
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.HookData; import com.genersoft.iot.vmp.media.event.hook.HookData;
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
@ -20,16 +19,13 @@ 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.RTPServerParam; import com.genersoft.iot.vmp.service.bean.RTPServerParam;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.utils.DateUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
@Service @Service
@ -53,7 +49,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
private HookSubscribe subscribe; private HookSubscribe subscribe;
@Autowired @Autowired
private RedisTemplate<Object, Object> redisTemplate; private SipInviteSessionManager sessionManager;
/** /**
* 流到来的处理 * 流到来的处理
@ -105,12 +101,12 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
log.warn("[openRTPServer] 平台对接时下级可能自定义ssrc但是tcp模式zlm收流目前无法更新ssrc可能收流超时此时请使用udp收流或者关闭ssrc校验"); log.warn("[openRTPServer] 平台对接时下级可能自定义ssrc但是tcp模式zlm收流目前无法更新ssrc可能收流超时此时请使用udp收流或者关闭ssrc校验");
} }
SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId); SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaApp.GB28181, streamId);
if (presetSSRC == null) { if (presetSSRC == null) {
ssrcInfo.setAllocatedSsrc(ssrc); ssrcInfo.setAllocatedSsrc(ssrc);
} }
RTPServerParam rtpServerParam = new RTPServerParam(mediaServer, MediaStreamUtil.RTP_APP, streamId, ssrcCheck ? Long.parseLong(ssrc): 0L, null, onlyAuto, disableAuto, false, tcpMode); RTPServerParam rtpServerParam = new RTPServerParam(mediaServer, MediaApp.GB28181, streamId, ssrcCheck ? Long.parseLong(ssrc): 0L, null, onlyAuto, disableAuto, false, tcpMode);
int rtpServerPort = openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { int rtpServerPort = openRTPServer(rtpServerParam, ((code, msg, data) -> {
if (code == InviteErrorCode.SUCCESS.getCode()) { if (code == InviteErrorCode.SUCCESS.getCode()) {
OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult(); OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult();
openRTPServerResult.setHookData(data); openRTPServerResult.setHookData(data);
@ -128,203 +124,11 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
} }
})); }));
ssrcInfo.setPort(rtpServerPort); ssrcInfo.setPort(rtpServerPort);
return new SSRCInfo(rtpServerPort, ssrc, MediaStreamUtil.RTP_APP, streamId); return new SSRCInfo(rtpServerPort, ssrc, MediaApp.GB28181, streamId);
} }
@Override @Override
public SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel, public int openRTPServer(RTPServerParam rtpServerParam, ErrorCallback<HookData> callback) {
String presetSSRC, boolean record, ErrorCallback<OpenRTPServerResult> callback) {
if (callback == null) {
log.warn("[开启国标点播RTP收流] 失败回调为NULL");
return null;
}
if (mediaServer == null) {
log.warn("[开启国标点播RTP收流] 失败媒体节点为NULL");
return null;
}
// 获取 mediaServer 可用的 ssrc
final String ssrc;
if (presetSSRC != null) {
ssrc = presetSSRC;
}else {
ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId());
}
String streamId;
String streamReplace = null;
if (mediaServer.isRtpEnable()) {
streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId());
}else {
streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();
streamReplace = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId());
}
int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
if (device.isSsrcCheck() && tcpMode > 0) {
// 目前zlm不支持 tcp模式更新ssrc暂时关闭ssrc校验
log.warn("[开启国标点播RTP收流] 平台对接时下级可能自定义ssrc但是tcp模式zlm收流目前无法更新ssrc可能收流超时此时请使用udp收流或者关闭ssrc校验");
}
Long checkSsrc = device.isSsrcCheck() ? Long.parseLong(ssrc) : 0L;
SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamReplace != null ? streamReplace : streamId);
if (presetSSRC == null) {
ssrcInfo.setAllocatedSsrc(ssrc);
}
openRtpServer(mediaServer, ssrcInfo, checkSsrc, !channel.isHasAudio(), false, tcpMode, callback);
addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), record, null);
return ssrcInfo;
}
@Override
public SSRCInfo openGbRTPServerForPlayback(MediaServer mediaServer, Device device, DeviceChannel channel,
String startTime, String endTime, ErrorCallback<OpenRTPServerResult> callback) {
if (callback == null) {
log.warn("[开启国标回放RTP收流] 失败回调为NULL");
return null;
}
if (mediaServer == null) {
log.warn("[开启国标回放RTP收流] 失败媒体节点为NULL");
return null;
}
// 获取 mediaServer 可用的 ssrc
String ssrc = ssrcFactory.getPlayBackSsrc(mediaServer.getId());
String streamId;
String streamReplace = null;
if (mediaServer.isRtpEnable()) {
streamId = getPlaybackStream(device, channel, startTime, endTime);
}else {
streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();
streamReplace = getPlaybackStream(device, channel, startTime, endTime);
}
int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
if (device.isSsrcCheck() && tcpMode > 0) {
// 目前zlm不支持 tcp模式更新ssrc暂时关闭ssrc校验
log.warn("[开启国标回放RTP收流] 平台对接时下级可能自定义ssrc但是tcp模式zlm收流目前无法更新ssrc可能收流超时此时请使用udp收流或者关闭ssrc校验");
}
Long checkSsrc = device.isSsrcCheck() ? Long.parseLong(ssrc) : 0L;
SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamReplace != null ? streamReplace : streamId);
ssrcInfo.setAllocatedSsrc(ssrc);
openRtpServer(mediaServer, ssrcInfo, checkSsrc, !channel.isHasAudio(), false, tcpMode, callback);
addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), false,null);
return ssrcInfo;
}
@Override
public String getPlaybackStream(Device device, DeviceChannel channel, String startTime, String endTime) {
String startTimeStr = startTime.replace("-", "")
.replace(":", "")
.replace(" ", "");
String endTimeTimeStr = endTime.replace("-", "")
.replace(":", "")
.replace(" ", "");
return device.getDeviceId() + "_" + channel.getDeviceId() + "_" + startTimeStr + "_" + endTimeTimeStr;
}
@Override
public SSRCInfo openGbRTPServerForDownload(MediaServer mediaServer, Device device, DeviceChannel channel,
String startTime, String endTime, ErrorCallback<OpenRTPServerResult> callback) {
if (callback == null) {
log.warn("[开启国标录像下载RTP收流] 失败回调为NULL");
return null;
}
if (mediaServer == null) {
log.warn("[开启国标录像下载RTP收流] 失败媒体节点为NULL");
return null;
}
int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
// 获取 mediaServer 可用的 ssrc
String ssrc = ssrcFactory.getPlayBackSsrc(mediaServer.getId());
String streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();
if (device.isSsrcCheck() && tcpMode > 0) {
// 目前zlm不支持 tcp模式更新ssrc暂时关闭ssrc校验
log.warn("[开启国标录像下载RTP收流] 平台对接时下级可能自定义ssrc但是tcp模式zlm收流目前无法更新ssrc可能收流超时此时请使用udp收流或者关闭ssrc校验");
}
Long checkSsrc = device.isSsrcCheck() ? Long.parseLong(ssrc) : 0L;
SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId);
ssrcInfo.setAllocatedSsrc(ssrc);
openRtpServer(mediaServer, ssrcInfo, checkSsrc, !channel.isHasAudio(), false, tcpMode, callback);
long difference = DateUtil.getDifference(startTime, endTime) / 1000;
addAuthenticateInfo(streamId, null, !channel.isHasAudio(), true, (int) difference);
return ssrcInfo;
}
@Override
public SSRCInfo openGbRTPServerForBroadcast(MediaServer mediaServer, Platform platform, CommonGBChannel channel,
ErrorCallback<OpenRTPServerResult> callback) {
if (callback == null) {
log.warn("[开启国标喊话RTP收流] 失败回调为NULL");
return null;
}
if (mediaServer == null) {
log.warn("[开启国标喊话RTP收流] 失败媒体节点为NULL");
return null;
}
String streamId = null;
if (mediaServer.isRtpEnable()) {
streamId = String.format("%s_%s", platform.getServerGBId(), channel.getGbDeviceId());
}
// 默认不进行SSRC校验 TODO 后续可改为配置
int tcpMode;
if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-PASSIVE")) {
tcpMode = 1;
}else if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) {
tcpMode = 2;
} else {
tcpMode = 0;
}
// 获取 mediaServer 可用的 ssrc
String ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId());
SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId);
ssrcInfo.setAllocatedSsrc(ssrc);
openRtpServer(mediaServer, ssrcInfo, 0L, false, true, tcpMode, callback);
return ssrcInfo;
}
private void openRtpServer(MediaServer mediaServer, SSRCInfo ssrcInfo, Long checkSsrc, boolean disableAuto, boolean onlyAuto, int tcpMode,
ErrorCallback<OpenRTPServerResult> callback) {
RTPServerParam rtpServerParam = new RTPServerParam(mediaServer, MediaStreamUtil.RTP_APP, ssrcInfo.getStream(), checkSsrc, null, onlyAuto, disableAuto, false, tcpMode);
int rtpServerPort = openCommonRTPServer(rtpServerParam, ((code, msg, data) -> {
if (code == InviteErrorCode.SUCCESS.getCode()) {
OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult();
openRTPServerResult.setHookData(data);
openRTPServerResult.setSsrcInfo(ssrcInfo);
callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), openRTPServerResult);
} else {
// 释放ssrc
if (ssrcInfo.getAllocatedSsrc() != null) {
ssrcFactory.releaseSsrc(mediaServer.getId(), ssrcInfo.getAllocatedSsrc());
ssrcInfo.setAllocatedSsrc(null);
}
OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult();
openRTPServerResult.setSsrcInfo(ssrcInfo);
callback.run(code, msg, openRTPServerResult);
}
}));
ssrcInfo.setPort(rtpServerPort);
}
@Override
public int openCommonRTPServer(RTPServerParam rtpServerParam, ErrorCallback<HookData> callback) {
if (callback == null) { if (callback == null) {
log.warn("[开启RTP收流] 失败回调为NULL"); log.warn("[开启RTP收流] 失败回调为NULL");
return -1; return -1;
@ -377,10 +181,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
if (dynamicTask.contains(timeOutTaskKey)) { if (dynamicTask.contains(timeOutTaskKey)) {
dynamicTask.stop(timeOutTaskKey); dynamicTask.stop(timeOutTaskKey);
} }
if (mediaServer.isRtpEnable()) { mediaServerService.closeRTPServer(mediaServer, app, stream);
mediaServerService.closeRTPServer(mediaServer, app, stream);
}
mediaServerService.closeStreams(mediaServer, app, stream);
} }
@Override @Override
@ -391,39 +192,4 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
} }
closeRTPServer(mediaServer, app, stream); closeRTPServer(mediaServer, app, stream);
} }
@Override
public void addAuthenticateInfoForGb28181Talk(MediaServer mediaServer, String streamId) {
String streamReplace = null;
if (!mediaServer.isRtpEnable() ) {
streamReplace = streamId;
}
addAuthenticateInfo(streamId, streamReplace, true, false, null);
}
@Override
public void addAuthenticateInfo(String streamId, String streamReplace, Boolean enableAudio, Boolean enableMp4, Integer mp4MaxSecond) {
ResultForOnPublish hookResultForOnPublish = new ResultForOnPublish();
hookResultForOnPublish.setStream_replace(streamReplace);
hookResultForOnPublish.setEnable_audio(enableAudio);
hookResultForOnPublish.setEnable_mp4(enableMp4);
hookResultForOnPublish.setMp4_max_second(mp4MaxSecond);
String key = String.format("%s:%s", VideoManagerConstants.RTP_AUTHENTICATE, streamId);
// 存储认证信息过期时间为60秒 过期则无法通过认证
redisTemplate.opsForValue().set(key, hookResultForOnPublish);
redisTemplate.expire(key, 60, TimeUnit.SECONDS);
}
@Override
public ResultForOnPublish getAuthenticateInfo(String streamId) {
String key = String.format("%s:%s", VideoManagerConstants.RTP_AUTHENTICATE, streamId);
Object obj = redisTemplate.opsForValue().get(key);
if (obj instanceof ResultForOnPublish) {
return (ResultForOnPublish) obj;
}
return null;
}
} }

View File

@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.streamProxy.service.impl;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.common.enums.ChannelDataType;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
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.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
@ -104,7 +104,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
@Async @Async
@EventListener @EventListener
public void onApplicationEvent(MediaNotFoundEvent event) { public void onApplicationEvent(MediaNotFoundEvent event) {
if (MediaStreamUtil.isKeywords(event.getApp())) { if (MediaApp.isKeywords(event.getApp())) {
return; return;
} }
// 拉流代理 // 拉流代理

View File

@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.streamPush.service.impl;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
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.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
@ -102,7 +102,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
updatePushStatus(streamPushInDb); updatePushStatus(streamPushInDb);
} }
// 冗余数据自己系统中自用 // 冗余数据自己系统中自用
if (!MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp()) && !MediaStreamUtil.GB28181_TALK.equals(event.getApp())) { if (!MediaApp.GB28181_BROADCAST.equals(event.getApp()) && !MediaApp.GB28181_TALK.equals(event.getApp())) {
redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event.getMediaInfo()); redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event.getMediaInfo());
} }

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.vmanager.ps; package com.genersoft.iot.vmp.vmanager.ps;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
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.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.exception.ControllerException;
@ -16,6 +16,7 @@ import com.genersoft.iot.vmp.service.IReceiveRtpServerService;
import com.genersoft.iot.vmp.service.ISendRtpServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.service.bean.RTPServerParam; import com.genersoft.iot.vmp.service.bean.RTPServerParam;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo; import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
@ -101,12 +102,12 @@ public class PsController {
RTPServerParam rtpServerParam = new RTPServerParam(); RTPServerParam rtpServerParam = new RTPServerParam();
rtpServerParam.setMediaServer(mediaServer); rtpServerParam.setMediaServer(mediaServer);
rtpServerParam.setApp(MediaStreamUtil.RTP_APP); rtpServerParam.setApp(MediaApp.GB28181);
rtpServerParam.setStreamId(stream); rtpServerParam.setStreamId(stream);
rtpServerParam.setSsrc(ssrcInt); rtpServerParam.setSsrc(ssrcInt);
rtpServerParam.setTcpMode(tcpMode); rtpServerParam.setTcpMode(tcpMode);
int rtpServerPort = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { int rtpServerPort = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> {
if (callBack == null) { if (callBack == null) {
return; return;
} }
@ -133,10 +134,6 @@ public class PsController {
if (rtpServerPort == 0) { if (rtpServerPort == 0) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败"); throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败");
} }
// 补充鉴权参数
receiveRtpServerService.addAuthenticateInfo(stream, null, false, false, null);
OtherPsSendInfo otherPsSendInfo = new OtherPsSendInfo(); OtherPsSendInfo otherPsSendInfo = new OtherPsSendInfo();
otherPsSendInfo.setReceiveIp(mediaServer.getSdpIp()); otherPsSendInfo.setReceiveIp(mediaServer.getSdpIp());
otherPsSendInfo.setReceivePort(rtpServerPort); otherPsSendInfo.setReceivePort(rtpServerPort);
@ -166,7 +163,7 @@ public class PsController {
public void closeRtpServer(String stream) { public void closeRtpServer(String stream) {
log.info("[第三方PS服务对接->关闭收流] stream->{}", stream); log.info("[第三方PS服务对接->关闭收流] stream->{}", stream);
MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer(); MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
receiveRtpServerService.closeRTPServer(mediaServerItem, MediaStreamUtil.RTP_APP, stream); receiveRtpServerService.closeRTPServer(mediaServerItem, MediaApp.GB28181, stream);
String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_*_" + stream; String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_*_" + stream;
List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey); List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey);
if (!scan.isEmpty()) { if (!scan.isEmpty()) {

View File

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.vmanager.rtp; package com.genersoft.iot.vmp.vmanager.rtp;
import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
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.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.exception.ControllerException;
@ -16,6 +16,7 @@ import com.genersoft.iot.vmp.service.IReceiveRtpServerService;
import com.genersoft.iot.vmp.service.ISendRtpServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.service.bean.RTPServerParam; import com.genersoft.iot.vmp.service.bean.RTPServerParam;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
@ -101,13 +102,13 @@ public class RtpController {
RTPServerParam rtpServerParam = new RTPServerParam(); RTPServerParam rtpServerParam = new RTPServerParam();
rtpServerParam.setMediaServer(mediaServer); rtpServerParam.setMediaServer(mediaServer);
rtpServerParam.setApp(MediaStreamUtil.RTP_APP); rtpServerParam.setApp(MediaApp.GB28181);
rtpServerParam.setStreamId(stream); rtpServerParam.setStreamId(stream);
rtpServerParam.setSsrc(ssrcInt); rtpServerParam.setSsrc(ssrcInt);
rtpServerParam.setTcpMode(tcpMode); rtpServerParam.setTcpMode(tcpMode);
int rtpServerPortForVideo = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { int rtpServerPortForVideo = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> {
if (callBack == null) { if (callBack == null) {
return; return;
} }
@ -126,21 +127,16 @@ public class RtpController {
log.info("[开启收流和获取发流信息] 视频流收流失败callId->{}stream->{}", callId, stream); log.info("[开启收流和获取发流信息] 视频流收流失败callId->{}stream->{}", callId, stream);
} }
})); }));
// 补充鉴权参数
receiveRtpServerService.addAuthenticateInfo(stream, null, false, false, null);
rtpServerParam.setStreamId(stream + "_a"); rtpServerParam.setStreamId(stream + "_a");
int rtpServerPortForAudio = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { int rtpServerPortForAudio = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> {
if (code == InviteErrorCode.SUCCESS.getCode()) { if (code == InviteErrorCode.SUCCESS.getCode()) {
log.info("[开启收流和获取发流信息] 音频流收流成功callId->{}stream->{}", callId, stream); log.info("[开启收流和获取发流信息] 音频流收流成功callId->{}stream->{}", callId, stream);
}else { }else {
log.info("[开启收流和获取发流信息] 音频流收流失败callId->{}stream->{}", callId, stream); log.info("[开启收流和获取发流信息] 音频流收流失败callId->{}stream->{}", callId, stream);
} }
})); }));
// 补充鉴权参数
receiveRtpServerService.addAuthenticateInfo(rtpServerParam.getStreamId(), null, true, false, null);
if (rtpServerPortForVideo == 0 || rtpServerPortForAudio == 0) { if (rtpServerPortForVideo == 0 || rtpServerPortForAudio == 0) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败"); throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败");
} }
@ -178,8 +174,8 @@ public class RtpController {
public void closeRtpServer(String stream) { public void closeRtpServer(String stream) {
log.info("[第三方服务对接->关闭收流] stream->{}", stream); log.info("[第三方服务对接->关闭收流] stream->{}", stream);
MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer(); MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
receiveRtpServerService.closeRTPServer(mediaServerItem, MediaStreamUtil.RTP_APP, stream); receiveRtpServerService.closeRTPServer(mediaServerItem, MediaApp.GB28181, stream);
receiveRtpServerService.closeRTPServer(mediaServerItem, MediaStreamUtil.RTP_APP, stream+ "_a"); receiveRtpServerService.closeRTPServer(mediaServerItem, MediaApp.GB28181, stream+ "_a");
String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_*_" + stream; String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_*_" + stream;
List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey); List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey);
if (scan.size() > 0) { if (scan.size() > 0) {

View File

@ -4,7 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.InviteInfo; import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.common.enums.MediaApp;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Device;
@ -247,7 +247,7 @@ public class ApiStreamController {
} }
try { try {
cmder.streamByeCmd(device, code, MediaStreamUtil.RTP_APP, inviteInfo.getStream(), null, null); cmder.streamByeCmd(device, code, MediaApp.GB28181, inviteInfo.getStream(), null, null);
} catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
result.put("error","发送BYE失败" + e.getMessage()); result.put("error","发送BYE失败" + e.getMessage());

View File

@ -11,9 +11,8 @@
<script type="text/javascript" src="./static/js/jessibuca/jessibuca.js"></script> <script type="text/javascript" src="./static/js/jessibuca/jessibuca.js"></script>
<script type="text/javascript" src="./static/js/ZLMRTCClient.js"></script> <script type="text/javascript" src="./static/js/ZLMRTCClient.js"></script>
<script type="text/javascript" src="./static/js/config.js"></script> <script type="text/javascript" src="./static/js/config.js"></script>
<!-- <script type="text/javascript" src="./static/js/h265web2/h265web.js"></script>--> <script type="text/javascript" src="./static/js/h265web2/h265web.js"></script>
<script type="text/javascript" src="./static/js/h265web/h265webjs-v20221106.js"></script> <!-- <script type="text/javascript" src="./static/js/h265web/missile.js"></script>-->
<script type="text/javascript" src="./static/js/h265web/missile.js"></script>
<noscript> <noscript>
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> <strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript> </noscript>

View File

@ -157,7 +157,7 @@ export function startPlayback(params) {
const { phoneNumber, channelId, startTime, endTime, type, rate, playbackType, playbackSpeed } = params const { phoneNumber, channelId, startTime, endTime, type, rate, playbackType, playbackSpeed } = params
return request({ return request({
method: 'get', method: 'get',
url: '/api/jt1078/playback/start', url: '/api/jt1078/playback/start/',
params: { params: {
phoneNumber: phoneNumber, phoneNumber: phoneNumber,
channelId: channelId, channelId: channelId,
@ -204,7 +204,7 @@ export function stopPlayback(params) {
const { phoneNumber, channelId, streamId } = params const { phoneNumber, channelId, streamId } = params
return request({ return request({
method: 'get', method: 'get',
url: '/api/jt1078/playback/stop', url: '/api/jt1078/playback/stop/',
params: { params: {
phoneNumber: phoneNumber, phoneNumber: phoneNumber,
channelId: channelId, channelId: channelId,

View File

@ -134,34 +134,48 @@ export default {
}, },
create(url) { create(url) {
this.playerLoading = true this.playerLoading = true
const options = {} const options = {
h265webPlayer[this._uid] = new window.new265webjs(url, Object.assign( player_id: 'glplayer',
{ base_url: './static/js/h265web2/',
player: 'glplayer', // id wasm_js_uri: 'h265web_wasm.js',
width: this.playerWidth, wasm_wasm_uri: 'h265web_wasm.wasm',
height: this.playerHeight, ext_src_js_uri: 'extjs.js',
token: token, ext_wasm_js_uri: 'extwasm.js',
extInfo: { width: '100%',
coreProbePart: 0.4, height: 480,
probeSize: 8192, color: '#101318',
ignoreAudio: this.hasAudio === null ? 0 : (this.hasAudio ? 0 : 1) auto_play: false,
} readframe_multi_times: -1,
}, ignore_audio: false
options }
))
h265webPlayer[this._uid] = H265webjsPlayer()
const h265web = h265webPlayer[this._uid] const h265web = h265webPlayer[this._uid]
h265web.on_ready_show_done_callback = () => {
console.log('ready_show_done_callback')
h265web.play()
console.log('ready_show_done_callback---22')
this.playing = true
this.playerLoading = false
}
h265web.video_probe_callback = (mediaInfo) => {
console.log('video_probe_callback: ', mediaInfo)
}
h265web.build(options)
h265web.load_media(url)
h265web.onOpenFullScreen = () => { h265web.onOpenFullScreen = () => {
this.fullscreen = true this.fullscreen = true
} }
h265web.onCloseFullScreen = () => { h265web.onCloseFullScreen = () => {
this.fullscreen = false this.fullscreen = false
} }
h265web.onReadyShowDone = () => {
//
const result = h265web.play()
this.playing = result
this.playerLoading = false
}
h265web.onLoadFinish = () => { h265web.onLoadFinish = () => {
this.loaded = true this.loaded = true
// mediaInfo // mediaInfo
@ -171,7 +185,7 @@ export default {
h265web.onPlayTime = (videoPTS) => { h265web.onPlayTime = (videoPTS) => {
this.$emit('playTimeChange', videoPTS * 1000) this.$emit('playTimeChange', videoPTS * 1000)
} }
h265web.do() // h265web.do()
}, },
screenshot: function() { screenshot: function() {
if (h265webPlayer[this._uid]) { if (h265webPlayer[this._uid]) {
@ -179,7 +193,7 @@ export default {
console.log(this.mediaInfo) console.log(this.mediaInfo)
canvas.width = this.mediaInfo.meta.size.width canvas.width = this.mediaInfo.meta.size.width
canvas.height = this.mediaInfo.meta.size.height canvas.height = this.mediaInfo.meta.size.height
h265webPlayer[this._uid].snapshot(canvas) // snapshot to canvas h265webPlayer[this._uid].screenshot(canvas) // snapshot to canvas
// //
const link = document.createElement('a') const link = document.createElement('a')
@ -213,14 +227,14 @@ export default {
unPause: function() { unPause: function() {
if (h265webPlayer[this._uid]) { if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].play() h265webPlayer[this._uid].play()
this.playing = h265webPlayer[this._uid].isPlaying() this.playing = true
} }
this.err = '' this.err = ''
}, },
pause: function() { pause: function() {
if (h265webPlayer[this._uid]) { if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].pause() h265webPlayer[this._uid].pause()
this.playing = h265webPlayer[this._uid].isPlaying() this.playing = false
} }
this.err = '' this.err = ''
}, },

View File

@ -1,344 +0,0 @@
<template>
<div id="h265Player" ref="container" style="background-color: #000000; " @dblclick="fullscreenSwich">
<div id="glplayer" ref="playerBox" style="width: 100%; height: 100%; margin: 0 auto;" >
<div v-if="playerLoading" class="play-loading">
<i class="el-icon-loading" />
视频加载中
</div>
</div>
<div v-if="showButton" id="buttonsBox" class="buttons-box">
<div class="buttons-box-left">
<i v-if="!playing" class="iconfont icon-play h265web-btn" @click="unPause" />
<i v-if="playing" class="iconfont icon-pause h265web-btn" @click="pause" />
<i class="iconfont icon-stop h265web-btn" @click="destroy" />
<i v-if="isNotMute" class="iconfont icon-audio-high h265web-btn" @click="mute()" />
<i v-if="!isNotMute" class="iconfont icon-audio-mute h265web-btn" @click="cancelMute()" />
</div>
<div class="buttons-box-right">
<!-- <i class="iconfont icon-file-record1 h265web-btn"></i>-->
<!-- <i class="iconfont icon-xiangqing2 h265web-btn" ></i>-->
<i
class="iconfont icon-camera1196054easyiconnet h265web-btn"
style="font-size: 1rem !important"
@click="screenshot"
/>
<i class="iconfont icon-shuaxin11 h265web-btn" @click="playBtnClick" />
<i v-if="!fullscreen" class="iconfont icon-weibiaoti10 h265web-btn" @click="fullscreenSwich" />
<i v-if="fullscreen" class="iconfont icon-weibiaoti11 h265web-btn" @click="fullscreenSwich" />
</div>
</div>
</div>
</template>
<script>
const h265webPlayer = {}
/**
* 从github上复制的
* @see https://github.com/numberwolf/h265web.js/blob/master/example_normal/index.js
*/
const token = 'base64:QXV0aG9yOmNoYW5neWFubG9uZ3xudW1iZXJ3b2xmLEdpdGh1YjpodHRwczovL2dpdGh1Yi5jb20vbnVtYmVyd29sZixFbWFpbDpwb3JzY2hlZ3QyM0Bmb3htYWlsLmNvbSxRUTo1MzEzNjU4NzIsSG9tZVBhZ2U6aHR0cDovL3h2aWRlby52aWRlbyxEaXNjb3JkOm51bWJlcndvbGYjODY5NCx3ZWNoYXI6bnVtYmVyd29sZjExLEJlaWppbmcsV29ya0luOkJhaWR1'
export default {
name: 'H265web',
props: ['videoUrl', 'error', 'hasAudio', 'height', 'showButton'],
data() {
return {
playing: false,
isNotMute: false,
quieting: false,
fullscreen: false,
loaded: false, // mute
speed: 0,
kBps: 0,
btnDom: null,
videoInfo: null,
volume: 1,
rotate: 0,
vod: true, //
forceNoOffscreen: false,
playerWidth: 0,
playerHeight: 0,
inited: false,
playerLoading: false,
mediaInfo: null
}
},
watch: {
videoUrl(newData, oldData) {
this.play(newData)
},
playing(newData, oldData) {
this.$emit('playStatusChange', newData)
},
immediate: true
},
mounted() {
const paramUrl = decodeURIComponent(this.$route.params.url)
window.onresize = () => {
this.updatePlayerDomSize()
}
this.btnDom = document.getElementById('buttonsBox')
console.log('初始化时的地址为: ' + paramUrl)
if (paramUrl) {
this.play(this.videoUrl)
}
},
destroyed() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].destroy()
}
this.playing = false
this.loaded = false
this.playerLoading = false
},
methods: {
updatePlayerDomSize() {
const dom = this.$refs.container
if (!this.parentNodeResizeObserver) {
this.parentNodeResizeObserver = new ResizeObserver(entries => {
this.updatePlayerDomSize()
})
this.parentNodeResizeObserver.observe(dom.parentNode)
}
const boxWidth = dom.parentNode.clientWidth
const boxHeight = dom.parentNode.clientHeight
let width = boxWidth
let height = (9 / 16) * width
if (boxHeight > 0 && boxWidth > boxHeight / 9 * 16) {
height = boxHeight
width = boxHeight / 9 * 16
}
const clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight)
if (height > clientHeight) {
height = clientHeight
width = (16 / 9) * height
}
this.$refs.playerBox.style.width = width + 'px'
this.$refs.playerBox.style.height = height + 'px'
this.playerWidth = width
this.playerHeight = height
if (this.playing) {
h265webPlayer[this._uid].resize(this.playerWidth, this.playerHeight)
}
},
resize(width, height) {
this.playerWidth = width
this.playerHeight = height
this.$refs.playerBox.style.width = width + 'px'
this.$refs.playerBox.style.height = height + 'px'
if (this.playing) {
h265webPlayer[this._uid].resize(this.playerWidth, this.playerHeight)
}
},
create(url) {
this.playerLoading = true
const options = {
player_id: 'glplayer',
base_url: './static/js/h265web2/',
wasm_js_uri: 'h265web_wasm.js',
wasm_wasm_uri: 'h265web_wasm.wasm',
ext_src_js_uri: 'extjs.js',
ext_wasm_js_uri: 'extwasm.js',
width: '100%',
height: 480,
color: '#101318',
auto_play: false,
readframe_multi_times: -1,
ignore_audio: false
}
h265webPlayer[this._uid] = H265webjsPlayer()
const h265web = h265webPlayer[this._uid]
h265web.on_ready_show_done_callback = () => {
console.log('ready_show_done_callback')
h265web.play()
console.log('ready_show_done_callback---22')
this.playing = true
this.playerLoading = false
}
h265web.video_probe_callback = (mediaInfo) => {
console.log('video_probe_callback: ', mediaInfo)
}
h265web.build(options)
h265web.load_media(url)
h265web.onOpenFullScreen = () => {
this.fullscreen = true
}
h265web.onCloseFullScreen = () => {
this.fullscreen = false
}
h265web.onLoadFinish = () => {
this.loaded = true
// mediaInfo
// @see https://github.com/numberwolf/h265web.js/blob/8b26a31ffa419bd0a0f99fbd5111590e144e36a8/example_normal/index.js#L252C9-L263C11
this.mediaInfo = h265web.mediaInfo()
}
h265web.onPlayTime = (videoPTS) => {
this.$emit('playTimeChange', videoPTS * 1000)
}
// h265web.do()
},
screenshot: function() {
if (h265webPlayer[this._uid]) {
const canvas = document.createElement('canvas')
console.log(this.mediaInfo)
canvas.width = this.mediaInfo.meta.size.width
canvas.height = this.mediaInfo.meta.size.height
h265webPlayer[this._uid].screenshot(canvas) // snapshot to canvas
//
const link = document.createElement('a')
link.download = 'screenshot.png'
link.href = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream')
link.click()
}
},
playBtnClick: function(event) {
this.play(this.videoUrl)
},
refresh: function() {
this.play(this.videoUrl)
},
play: function(url) {
if (h265webPlayer[this._uid]) {
this.destroy()
}
if (!url) {
return
}
if (this.playerWidth === 0 || this.playerHeight === 0) {
this.updatePlayerDomSize()
setTimeout(() => {
this.play(url)
}, 300)
return
}
this.create(url)
},
unPause: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].play()
this.playing = true
}
this.err = ''
},
pause: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].pause()
this.playing = false
}
this.err = ''
},
mute: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].setVoice(0.0)
this.isNotMute = false
}
},
cancelMute: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].setVoice(1.0)
this.isNotMute = true
}
},
destroy: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].release()
}
h265webPlayer[this._uid] = null
this.playing = false
this.err = ''
},
fullscreenSwich: function() {
const isFull = this.isFullscreen()
if (isFull) {
h265webPlayer[this._uid].closeFullScreen()
} else {
h265webPlayer[this._uid].fullScreen()
}
this.fullscreen = !isFull
},
isFullscreen: function() {
return document.fullscreenElement ||
document.msFullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement || false
},
setPlaybackRate: function(speed) {
h265webPlayer[this._uid].setPlaybackRate(speed)
}
}
}
</script>
<style>
.play-loading {
width: 100%;
height: 100%;
color: rgb(255, 255, 255);
display: flex;
align-items: center;
margin: 0 auto;
justify-content: center;
font-size: 18px;
}
.buttons-box {
width: 100%;
height: 28px;
background-color: rgba(43, 51, 63, 0.7);
position: absolute;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
left: 0;
bottom: 0;
user-select: none;
z-index: 10;
}
.h265web-btn {
width: 20px;
color: rgb(255, 255, 255);
line-height: 27px;
margin: 0px 10px;
padding: 0px 2px;
cursor: pointer;
text-align: center;
font-size: 0.8rem !important;
}
.buttons-box-right {
position: absolute;
right: 0;
}
.player-loading {
width: fit-content;
height: 30px;
position: absolute;
left: calc(50% - 52px);
top: calc(50% - 52px);
color: #fff;
font-size: 16px;
}
.player-loading i{
font-size: 24px;
line-height: 24px;
text-align: center;
display: block;
}
.player-loading span{
display: inline-block;
font-size: 16px;
height: 24px;
line-height: 24px;
}
</style>

View File

@ -65,22 +65,16 @@ export default {
.then(data => { .then(data => {
this.listChangeCallback() this.listChangeCallback()
}) })
.catch((error) => { .catch(function(error) {
this.$message.error({ console.log(error)
showClose: true,
message: error
})
}) })
} else { } else {
this.$store.dispatch('jtDevice/add', this.form) this.$store.dispatch('jtDevice/add', this.form)
.then(data => { .then(data => {
this.listChangeCallback() this.listChangeCallback()
}) })
.catch((error) => { .catch(function(error) {
this.$message.error({ console.log(error)
showClose: true,
message: error
})
}) })
} }
}, },