mirror of
https://gitee.com/pan648540858/wvp-GB28181-pro.git
synced 2026-05-06 14:07:49 +08:00
Compare commits
11 Commits
1091e359b9
...
2f58b59ad2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f58b59ad2 | ||
|
|
0984e8f1ed | ||
|
|
4a3a19379f | ||
|
|
37a4cb0ad7 | ||
|
|
a1441016f7 | ||
|
|
f961d6fc8d | ||
|
|
1e5ae10571 | ||
|
|
3e162ea358 | ||
|
|
ab3d0da115 | ||
|
|
e88d26b1e9 | ||
|
|
34d1dbb399 |
@ -35,16 +35,10 @@ public class InviteInfo {
|
||||
|
||||
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,
|
||||
String receiveIp, Integer receivePort, String streamMode,
|
||||
InviteSessionType type, InviteSessionStatus status, Boolean record) {
|
||||
InviteSessionType type, InviteSessionStatus status) {
|
||||
InviteInfo inviteInfo = new InviteInfo();
|
||||
inviteInfo.setDeviceId(deviceId);
|
||||
inviteInfo.setChannelId(channelId);
|
||||
@ -56,7 +50,6 @@ public class InviteInfo {
|
||||
inviteInfo.setType(type);
|
||||
inviteInfo.setStatus(status);
|
||||
inviteInfo.setMediaServerId(mediaServerId);
|
||||
inviteInfo.setRecord(record);
|
||||
return inviteInfo;
|
||||
}
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@ public class VideoManagerConstants {
|
||||
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 DRAW_THIN_PROCESS_PREFIX = "VMP_DRAW_THIN_PROCESS_";
|
||||
public static final String RTP_AUTHENTICATE = "VMP_RTP_AUTHENTICATE";
|
||||
|
||||
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ public class ChannelDataType {
|
||||
public final static String PLAYBACK_SERVICE = "sourceChannelPlaybackService";
|
||||
public final static String DOWNLOAD_SERVICE = "sourceChannelDownloadService";
|
||||
public final static String PTZ_SERVICE = "sourceChannelPTZService";
|
||||
public final static String OTHER_SERVICE = "sourceChannelOtherService";
|
||||
|
||||
|
||||
public static String getDateTypeDesc(Integer dataType) {
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
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]};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -106,7 +106,6 @@ public class JwtUtils implements InitializingBean {
|
||||
if (jwkFile == null || jwkFile.trim().isEmpty()) {
|
||||
log.warn("[API AUTH] JWK文件路径未配置!使用默认配置路径:./config/jwk.json");
|
||||
jwkFile = "config" + File.separator + "jwk.json"; // 默认外部路径
|
||||
return createAndPersistDefaultRsaKey(jwkFile);
|
||||
}
|
||||
|
||||
// 尝试读取JWK文件(自动处理classpath/本地文件,用try-with-resources自动关流,无泄露)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||
import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
|
||||
import lombok.Data;
|
||||
@ -205,7 +205,7 @@ public class SendRtpInfo {
|
||||
sendRtpItem.setChannelId(channelId);
|
||||
sendRtpItem.setTcp(isTcp);
|
||||
sendRtpItem.setRtcp(rtcp);
|
||||
sendRtpItem.setApp(MediaApp.GB28181);
|
||||
sendRtpItem.setApp(MediaStreamUtil.RTP_APP);
|
||||
sendRtpItem.setLocalPort(localPort);
|
||||
sendRtpItem.setServerId(serverId);
|
||||
sendRtpItem.setMediaServerId(mediaServer.getId());
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -73,9 +73,7 @@ public class DeviceControl {
|
||||
@Parameter(name = "guardCmd", description = "命令, 可选值:SetGuard(布防),ResetGuard(撤防)", required = true)
|
||||
@GetMapping("/guard")
|
||||
public DeferredResult<WVPResult<String>> guardApi(String deviceId, String guardCmd) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("布防/撤防API调用");
|
||||
}
|
||||
log.info("[布防/撤防] API调用, deviceId: {}, guardCmd: {}", deviceId, guardCmd);
|
||||
Device device = deviceService.getDeviceByDeviceId(deviceId);
|
||||
Assert.notNull(device, "设备不存在");
|
||||
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
|
||||
@ -109,9 +107,7 @@ public class DeviceControl {
|
||||
public DeferredResult<WVPResult<String>> resetAlarm(String deviceId, String channelId,
|
||||
@RequestParam(required = false) String alarmMethod,
|
||||
@RequestParam(required = false) String alarmType) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("报警复位API调用");
|
||||
}
|
||||
log.info("[报警复位] deviceId: {}, channelId: {}, alarmMethod: {}, alarmType: {}", deviceId, channelId, alarmMethod, alarmType);
|
||||
Device device = deviceService.getDeviceByDeviceId(deviceId);
|
||||
Assert.notNull(device, "设备不存在");
|
||||
DeferredResult<WVPResult<String>> result = new DeferredResult<>();
|
||||
|
||||
@ -67,9 +67,7 @@ public class GBRecordController {
|
||||
@GetMapping("/query/{deviceId}/{channelId}")
|
||||
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);
|
||||
if (!DateUtil.verification(startTime, DateUtil.formatter)){
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime格式为" + DateUtil.PATTERN);
|
||||
@ -113,9 +111,7 @@ public class GBRecordController {
|
||||
public DeferredResult<WVPResult<StreamContent>> download(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
|
||||
String startTime, String endTime, String downloadSpeed) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed));
|
||||
}
|
||||
log.info("[开始历史媒体下载] deviceId: {}, channelId: {}, startTime: {}, endTime: {}, downloadSpeed: {}", deviceId, channelId, startTime, endTime, downloadSpeed);
|
||||
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
|
||||
|
||||
@ -80,9 +80,7 @@ public class PlaybackController {
|
||||
public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
|
||||
String startTime, String endTime) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||
}
|
||||
log.info("[录像回放] deviceId: {}, channelId: {}, startTime: {}, endTime: {}", deviceId, channelId, startTime, endTime);
|
||||
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
package com.genersoft.iot.vmp.gb28181.service;
|
||||
|
||||
/**
|
||||
* 资源能力接入-其他
|
||||
*/
|
||||
public interface ISourceOtherService {
|
||||
|
||||
|
||||
Boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema);
|
||||
}
|
||||
@ -609,6 +609,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
|
||||
|
||||
@Override
|
||||
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())){
|
||||
redisRpcPlayService.queryRecordInfo(device.getServerId(), channel.getId(), startTime, endTime, callback);
|
||||
return;
|
||||
|
||||
@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.genersoft.iot.vmp.common.*;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.dao.DeviceChannelMapper;
|
||||
@ -50,7 +50,7 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
|
||||
@Async
|
||||
@EventListener
|
||||
public void onApplicationEvent(MediaDepartureEvent event) {
|
||||
if ("rtsp".equals(event.getSchema()) && MediaApp.GB28181.equals(event.getApp())) {
|
||||
if ("rtsp".equals(event.getSchema()) && MediaStreamUtil.isGB28181(event.getApp(), event.getStream())) {
|
||||
InviteInfo inviteInfo = getInviteInfoByStream(null, event.getStream());
|
||||
if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) {
|
||||
removeInviteInfo(inviteInfo);
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package com.genersoft.iot.vmp.gb28181.service.impl;
|
||||
|
||||
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.SipConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
@ -55,7 +54,6 @@ import javax.sip.ResponseEvent;
|
||||
import javax.sip.SipException;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -609,24 +607,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
|
||||
}
|
||||
}
|
||||
|
||||
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) -> {
|
||||
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForBroadcast(mediaServerItem, platform, channel, ((code, msg, data) -> {
|
||||
if (code == InviteErrorCode.SUCCESS.getCode() && data != null && data.getHookData() != null) {
|
||||
log.info("[国标级联] 发起语音喊话 收到上级推流 deviceId: {}, channelId: {}", platform.getServerGBId(), channel.getGbDeviceId());
|
||||
HookData hookData = data.getHookData();
|
||||
@ -664,15 +645,15 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
|
||||
return;
|
||||
}
|
||||
log.info("[国标级联] 语音喊话,发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
|
||||
platform.getServerGBId(), channel.getGbDeviceId(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), ssrcCheck);
|
||||
platform.getServerGBId(), channel.getGbDeviceId(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), false);
|
||||
|
||||
// 初始化redis中的invite消息状态
|
||||
InviteInfo inviteInfo = InviteInfo.getInviteInfo(platform.getServerGBId(), channel.getGbId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(),
|
||||
mediaServerItem.getSdpIp(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), InviteSessionType.BROADCAST,
|
||||
InviteSessionStatus.ready, userSetting.getRecordSip());
|
||||
InviteSessionStatus.ready);
|
||||
inviteStreamService.updateInviteInfo(inviteInfo);
|
||||
commanderForPlatform.broadcastInviteCmd(platform, channel,sourceId, mediaServerItem, ssrcInfo, event -> {
|
||||
inviteOKHandler(event, ssrcInfo, tcpMode, ssrcCheck, mediaServerItem, platform, channel,
|
||||
inviteOKHandler(event, ssrcInfo, false, mediaServerItem, platform, channel,
|
||||
null, inviteInfo, InviteSessionType.BROADCAST);
|
||||
}, eventResult -> {
|
||||
// 收到错误回复
|
||||
@ -694,7 +675,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
|
||||
}
|
||||
}
|
||||
|
||||
private void inviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, int tcpMode, boolean ssrcCheck, MediaServer mediaServerItem,
|
||||
private void inviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, boolean ssrcCheck, MediaServer mediaServerItem,
|
||||
Platform platform, CommonGBChannel channel, ErrorCallback<Object> callback,
|
||||
InviteInfo inviteInfo, InviteSessionType inviteSessionType){
|
||||
inviteInfo.setStatus(InviteSessionStatus.ok);
|
||||
@ -706,16 +687,11 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
|
||||
ssrcInResponse = ssrcInfo.getSsrc();
|
||||
}
|
||||
if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
|
||||
// ssrc 一致
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
// 多端口
|
||||
if (tcpMode == 2) {
|
||||
tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck,
|
||||
if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) {
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck,
|
||||
ssrcInfo, callback);
|
||||
}
|
||||
}else {
|
||||
// 单端口
|
||||
if (tcpMode == 2) {
|
||||
}else {
|
||||
log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
|
||||
}
|
||||
}
|
||||
@ -753,9 +729,9 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
|
||||
updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null);
|
||||
inviteInfo.setSsrcInfo(ssrcInfo);
|
||||
inviteInfo.setStream(ssrcInfo.getStream());
|
||||
if (tcpMode == 2) {
|
||||
if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) {
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck,
|
||||
tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck,
|
||||
ssrcInfo, callback);
|
||||
}else {
|
||||
log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
|
||||
@ -769,9 +745,9 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
|
||||
updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null);
|
||||
inviteInfo.setSsrcInfo(ssrcInfo);
|
||||
inviteInfo.setStream(ssrcInfo.getStream());
|
||||
if (tcpMode == 2) {
|
||||
if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) {
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck,
|
||||
tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck,
|
||||
ssrcInfo, callback);
|
||||
}else {
|
||||
log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
|
||||
@ -827,12 +803,8 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
|
||||
|
||||
|
||||
private void tcpActiveHandler(Platform platform, CommonGBChannel channel, String contentString,
|
||||
MediaServer mediaServerItem, int tcpMode, boolean ssrcCheck,
|
||||
MediaServer mediaServerItem, boolean ssrcCheck,
|
||||
SSRCInfo ssrcInfo, ErrorCallback<Object> callback){
|
||||
if (tcpMode != 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
String substring;
|
||||
if (contentString.indexOf("y=") > 0) {
|
||||
substring = contentString.substring(0, contentString.indexOf("y="));
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.genersoft.iot.vmp.gb28181.service.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.common.*;
|
||||
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.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
@ -133,7 +133,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
@Async
|
||||
@EventListener
|
||||
public void onApplicationEvent(MediaArrivalEvent event) {
|
||||
if (MediaApp.GB28181_BROADCAST.equals(event.getApp()) || MediaApp.GB28181_TALK.equals(event.getApp())) {
|
||||
if (MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp()) || MediaStreamUtil.GB28181_TALK.equals(event.getApp())) {
|
||||
if (event.getStream().indexOf("_") > 0) {
|
||||
String[] streamArray = event.getStream().split("_");
|
||||
if (streamArray.length == 2) {
|
||||
@ -149,7 +149,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
log.info("[语音对讲/喊话] 未找到通道:{}", channelId);
|
||||
return;
|
||||
}
|
||||
if (MediaApp.GB28181_BROADCAST.equals(event.getApp())) {
|
||||
if (MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp())) {
|
||||
if (audioBroadcastManager.exit(channel.getId())) {
|
||||
stopAudioBroadcast(device, channel);
|
||||
}
|
||||
@ -160,7 +160,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
} catch (InvalidArgumentException | ParseException | SipException e) {
|
||||
log.error("[命令发送失败] 语音对讲: {}", e.getMessage());
|
||||
}
|
||||
}else if (MediaApp.GB28181_TALK.equals(event.getApp())) {
|
||||
}else if (MediaStreamUtil.GB28181_TALK.equals(event.getApp())) {
|
||||
// 开启语音对讲通道
|
||||
talkCmd(device, channel, event.getMediaServer(), event.getStream(), (msg) -> log.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId));
|
||||
}
|
||||
@ -205,7 +205,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
}
|
||||
|
||||
if (MediaApp.GB28181_BROADCAST.equals(event.getApp()) || MediaApp.GB28181_TALK.equals(event.getApp())) {
|
||||
if (MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp()) || MediaStreamUtil.GB28181_TALK.equals(event.getApp())) {
|
||||
if (event.getStream().indexOf("_") > 0) {
|
||||
String[] streamArray = event.getStream().split("_");
|
||||
if (streamArray.length == 2) {
|
||||
@ -221,14 +221,14 @@ public class PlayServiceImpl implements IPlayService {
|
||||
log.info("[语音对讲/喊话] 未找到通道:{}", channelId);
|
||||
return;
|
||||
}
|
||||
if (MediaApp.GB28181_BROADCAST.equals(event.getApp())) {
|
||||
if (MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp())) {
|
||||
stopAudioBroadcast(device, channel);
|
||||
}else if (MediaApp.GB28181_TALK.equals(event.getApp())) {
|
||||
}else if (MediaStreamUtil.GB28181_TALK.equals(event.getApp())) {
|
||||
stopTalk(device, channel, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if (MediaApp.GB28181.equals(event.getApp())) {
|
||||
}else if (MediaStreamUtil.isGB28181(event.getApp(), event.getStream())) {
|
||||
// 释放ssrc
|
||||
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, event.getStream());
|
||||
if (inviteInfo != null && inviteInfo.getStatus() == InviteSessionStatus.ok
|
||||
@ -246,7 +246,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
@Async
|
||||
@EventListener
|
||||
public void onApplicationEvent(MediaNotFoundEvent event) {
|
||||
if (!MediaApp.GB28181.equals(event.getApp())) {
|
||||
if (!MediaStreamUtil.isGB28181(event.getApp(), event.getStream())) {
|
||||
return;
|
||||
}
|
||||
String[] s = event.getStream().split("_");
|
||||
@ -354,7 +354,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
return inviteInfoInCatch.getSsrcInfo();
|
||||
}
|
||||
MediaServer mediaInfo = streamInfo.getMediaServer();
|
||||
Boolean ready = mediaServerService.isStreamReady(mediaInfo, MediaApp.GB28181, streamId);
|
||||
Boolean ready = mediaServerService.isStreamReady(mediaInfo, MediaStreamUtil.RTP_APP, streamId);
|
||||
if (ready != null && ready) {
|
||||
if(callback != null) {
|
||||
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());
|
||||
int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0);
|
||||
|
||||
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServer, streamId, ssrc, tcpMode, false,
|
||||
device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> {
|
||||
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlay(mediaServer, device, channel, ssrc,
|
||||
record != null ? record : userSetting.getRecordSip(),
|
||||
(code, msg, result) -> {
|
||||
|
||||
if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) {
|
||||
// hook 响应
|
||||
@ -410,14 +410,14 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null, code, msg, null);
|
||||
inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
|
||||
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaApp.GB28181, streamId);
|
||||
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaStreamUtil.RTP_APP, streamId);
|
||||
if (ssrcTransaction != null) {
|
||||
try {
|
||||
cmder.streamByeCmd(device, channel.getDeviceId(),MediaApp.GB28181, streamId, null, null);
|
||||
cmder.streamByeCmd(device, channel.getDeviceId(), MediaStreamUtil.RTP_APP, streamId, null, null);
|
||||
} catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
|
||||
log.error("[点播超时], 发送BYE失败 {}", e.getMessage());
|
||||
} finally {
|
||||
sessionManager.removeByStream(MediaApp.GB28181, streamId);
|
||||
sessionManager.removeByStream(MediaStreamUtil.RTP_APP, streamId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -431,20 +431,15 @@ public class PlayServiceImpl implements IPlayService {
|
||||
null);
|
||||
return null;
|
||||
}
|
||||
log.info("[点播开始] 设备编号: {}, 通道编号: {}, 收流端口: {}, 流ID:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
|
||||
device.getDeviceId(), channel.getDeviceId(), ssrcInfo.getPort(), ssrcInfo.getStream(), channel.getStreamIdentification(),
|
||||
String sdpIp = !ObjectUtils.isEmpty(device.getSdpIp()) ? device.getSdpIp() : mediaServer.getSdpIp();
|
||||
log.info("[点播开始] 设备编号: {}, 通道编号: {}, 收流地址: {}:{}, 流ID:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
|
||||
device.getDeviceId(), channel.getDeviceId(), sdpIp, ssrcInfo.getPort(), ssrcInfo.getStream(), device.getStreamMode(),
|
||||
ssrcInfo.getSsrc(), device.isSsrcCheck());
|
||||
|
||||
// 初始化redis中的invite消息状态
|
||||
InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(),
|
||||
mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY,
|
||||
InviteSessionStatus.ready, userSetting.getRecordSip());
|
||||
if (record != null) {
|
||||
inviteInfo.setRecord(record);
|
||||
}else {
|
||||
inviteInfo.setRecord(userSetting.getRecordSip());
|
||||
}
|
||||
|
||||
InviteSessionStatus.ready);
|
||||
inviteStreamService.updateInviteInfo(inviteInfo);
|
||||
|
||||
try {
|
||||
@ -493,7 +488,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
SendRtpInfo sendRtpInfo;
|
||||
try {
|
||||
sendRtpInfo = sendRtpServerService.createSendRtpInfo(mediaServerItem, null, null, playSsrc, device.getDeviceId(), MediaApp.GB28181_TALK, stream,
|
||||
sendRtpInfo = sendRtpServerService.createSendRtpInfo(mediaServerItem, null, null, playSsrc, device.getDeviceId(), MediaStreamUtil.GB28181_TALK, stream,
|
||||
channel.getId(), true, false);
|
||||
if (sendRtpInfo == null) {
|
||||
ssrcFactory.releaseSsrc(mediaServerItem.getId(), playSsrc);
|
||||
@ -544,6 +539,9 @@ public class PlayServiceImpl implements IPlayService {
|
||||
return;
|
||||
}
|
||||
sendRtpInfo.setPort(localPort);
|
||||
// 增加鉴权信息
|
||||
receiveRtpServerService.addAuthenticateInfoForGb28181Talk(mediaServerItem, sendRtpInfo.getStream());
|
||||
|
||||
}catch (ControllerException e) {
|
||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpInfo.getSsrcToRelease());
|
||||
log.info("[语音对讲]失败 deviceId: {}, channelId: {}", device.getDeviceId(), channel.getDeviceId());
|
||||
@ -680,7 +678,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
String fileName = deviceId + "_" + channelId + ".jpg";
|
||||
// 请求截图
|
||||
log.info("[请求截图]: " + fileName);
|
||||
mediaServerService.getSnap(mediaServerItemInuse, MediaApp.GB28181, stream, 15, 1, path, fileName);
|
||||
mediaServerService.getSnap(mediaServerItemInuse, MediaStreamUtil.RTP_APP, stream, 15, 1, path, fileName);
|
||||
}
|
||||
|
||||
public StreamInfo onPublishHandlerForPlay(MediaServer mediaServerItem, MediaInfo mediaInfo, Device device, DeviceChannel channel) {
|
||||
@ -762,18 +760,9 @@ public class PlayServiceImpl implements IPlayService {
|
||||
Device device, DeviceChannel channel, String startTime,
|
||||
String endTime, ErrorCallback<StreamInfo> callback) {
|
||||
|
||||
String startTimeStr = startTime.replace("-", "")
|
||||
.replace(":", "")
|
||||
.replace(" ", "");
|
||||
String endTimeTimeStr = endTime.replace("-", "")
|
||||
.replace(":", "")
|
||||
.replace(" ", "");
|
||||
String stream = receiveRtpServerService.getPlaybackStream(device, channel, startTime, endTime);
|
||||
|
||||
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) -> {
|
||||
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlayback(mediaServer, device, channel, startTime, endTime, (code, msg, result) -> {
|
||||
if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) {
|
||||
// hook响应
|
||||
StreamInfo streamInfo = onPublishHandlerForPlayback(result.getHookData().getMediaServer(), result.getHookData().getMediaInfo(), device, channel, startTime, endTime);
|
||||
@ -791,14 +780,14 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
inviteStreamService.call(InviteSessionType.PLAYBACK, channel.getId(), null, code, msg, null);
|
||||
inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, channel.getId());
|
||||
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaApp.GB28181, stream);
|
||||
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaStreamUtil.RTP_APP, stream);
|
||||
if (ssrcTransaction != null) {
|
||||
try {
|
||||
cmder.streamByeCmd(device, channel.getDeviceId(),MediaApp.GB28181, stream, null, null);
|
||||
cmder.streamByeCmd(device, channel.getDeviceId(), MediaStreamUtil.RTP_APP, stream, null, null);
|
||||
} catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
|
||||
log.error("[录像回放] 发送BYE失败 {}", e.getMessage());
|
||||
} finally {
|
||||
sessionManager.removeByStream(MediaApp.GB28181, stream);
|
||||
sessionManager.removeByStream(MediaStreamUtil.RTP_APP, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -816,12 +805,12 @@ public class PlayServiceImpl implements IPlayService {
|
||||
}
|
||||
|
||||
log.info("[录像回放] deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
|
||||
device.getDeviceId(), channel.getGbDeviceId(), startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(),
|
||||
device.getDeviceId(), channel.getDeviceId(), startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(),
|
||||
ssrcInfo.getSsrc(), device.isSsrcCheck());
|
||||
// 初始化redis中的invite消息状态
|
||||
InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(),
|
||||
mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK,
|
||||
InviteSessionStatus.ready, userSetting.getRecordSip());
|
||||
InviteSessionStatus.ready);
|
||||
inviteStreamService.updateInviteInfo(inviteInfo);
|
||||
|
||||
try {
|
||||
@ -939,19 +928,19 @@ public class PlayServiceImpl implements IPlayService {
|
||||
if (ssrcInResponse != null) {
|
||||
// 单端口
|
||||
// 重新订阅流上线
|
||||
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaApp.GB28181, inviteInfo.getStream());
|
||||
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaStreamUtil.RTP_APP, inviteInfo.getStream());
|
||||
if (ssrcTransaction == null) {
|
||||
return;
|
||||
}
|
||||
releaseAllocatedSsrc(mediaServerItem, ssrcInfo);
|
||||
sessionManager.removeByStream(MediaApp.GB28181, inviteInfo.getStream());
|
||||
sessionManager.removeByStream(MediaStreamUtil.RTP_APP, inviteInfo.getStream());
|
||||
inviteStreamService.updateInviteInfoForSSRC(inviteInfo, ssrcInResponse);
|
||||
ssrcTransaction.setDeviceId(device.getDeviceId());
|
||||
ssrcTransaction.setChannelId(ssrcTransaction.getChannelId());
|
||||
ssrcTransaction.setCallId(ssrcTransaction.getCallId());
|
||||
ssrcTransaction.setSsrc(ssrcInResponse);
|
||||
ssrcTransaction.setAllocatedSsrc(null);
|
||||
ssrcTransaction.setApp(MediaApp.GB28181);
|
||||
ssrcTransaction.setApp(MediaStreamUtil.RTP_APP);
|
||||
ssrcTransaction.setStream(inviteInfo.getStream());
|
||||
ssrcTransaction.setMediaServerId(mediaServerItem.getId());
|
||||
ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo((SIPResponse) responseEvent.getResponse()));
|
||||
@ -1009,10 +998,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
return;
|
||||
}
|
||||
|
||||
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) -> {
|
||||
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForDownload(mediaServer, device, channel, startTime, endTime, (code, msg, result) -> {
|
||||
if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) {
|
||||
// hook响应
|
||||
StreamInfo streamInfo = onPublishHandlerForDownload(mediaServer, result.getHookData().getMediaInfo(), device, channel, startTime, endTime);
|
||||
@ -1063,10 +1049,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
// 初始化redis中的invite消息状态
|
||||
InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServer.getId(),
|
||||
mediaServer.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD,
|
||||
InviteSessionStatus.ready, true);
|
||||
inviteInfo.setStartTime(startTime);
|
||||
inviteInfo.setEndTime(endTime);
|
||||
|
||||
InviteSessionStatus.ready);
|
||||
inviteStreamService.updateInviteInfo(inviteInfo);
|
||||
try {
|
||||
cmder.downloadStreamCmd(mediaServer, ssrcInfo, device, channel, startTime, endTime, downloadSpeed,
|
||||
@ -1096,7 +1079,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
inviteStreamService.updateInviteInfo(inviteInfoForNew, 60*15L);
|
||||
}
|
||||
};
|
||||
Hook hook = Hook.getInstance(HookType.on_record_mp4, MediaApp.GB28181, ssrcInfo.getStream(), mediaServer.getId());
|
||||
Hook hook = Hook.getInstance(HookType.on_record_mp4, MediaStreamUtil.RTP_APP, ssrcInfo.getStream(), mediaServer.getId());
|
||||
// 设置过期时间,下载失败时自动处理订阅数据
|
||||
hook.setExpireTime(System.currentTimeMillis() + 24 * 60 * 60 * 1000);
|
||||
subscribe.addSubscribe(hook, hookEventForRecord);
|
||||
@ -1116,7 +1099,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
|
||||
InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, channel.getId(), stream);
|
||||
if (inviteInfo == null) {
|
||||
String app = MediaApp.GB28181;
|
||||
String app = MediaStreamUtil.RTP_APP;
|
||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
|
||||
if (streamAuthorityInfo != null) {
|
||||
List<CloudRecordItem> allList = cloudRecordService.getAllList(null, app, stream, null, null, null, streamAuthorityInfo.getCallId(), null);
|
||||
@ -1158,7 +1141,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
log.warn("[获取下载进度] 查询录像信息时发现节点不存在");
|
||||
return null;
|
||||
}
|
||||
String app = MediaApp.GB28181;
|
||||
String app = MediaStreamUtil.RTP_APP;
|
||||
Long duration = mediaServerService.updateDownloadProcess(mediaServerItem, app, stream);
|
||||
if (duration == null || duration == 0) {
|
||||
inviteInfo.getStreamInfo().setProgress(0);
|
||||
@ -1201,7 +1184,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
|
||||
|
||||
public StreamInfo onPublishHandler(MediaServer mediaServerItem, MediaInfo mediaInfo, Device device, DeviceChannel channel) {
|
||||
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, MediaApp.GB28181, mediaInfo.getStream(), mediaInfo, null);
|
||||
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, MediaStreamUtil.RTP_APP, mediaInfo.getStream(), mediaInfo, null);
|
||||
streamInfo.setDeviceId(device.getDeviceId());
|
||||
streamInfo.setChannelId(channel.getId());
|
||||
return streamInfo;
|
||||
@ -1270,7 +1253,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
if (broadcastMode == null) {
|
||||
broadcastMode = true;
|
||||
}
|
||||
String app = broadcastMode ? MediaApp.GB28181_BROADCAST : MediaApp.GB28181_TALK;
|
||||
String app = broadcastMode ? MediaStreamUtil.GB28181_BROADCAST : MediaStreamUtil.GB28181_TALK;
|
||||
String stream = device.getDeviceId() + "_" + deviceChannel.getDeviceId();
|
||||
AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult();
|
||||
audioBroadcastResult.setApp(app);
|
||||
@ -1572,7 +1555,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
SendRtpInfo sendRtpInfo = sendRtpServerService.queryByChannelId(channel.getId(), device.getDeviceId());
|
||||
if (sendRtpInfo != null) {
|
||||
MediaServer mediaServer = mediaServerService.getOne(sendRtpInfo.getMediaServerId());
|
||||
Boolean streamReady = mediaServerService.isStreamReady(mediaServer, MediaApp.GB28181_TALK, sendRtpInfo.getReceiveStream());
|
||||
Boolean streamReady = mediaServerService.isStreamReady(mediaServer, MediaStreamUtil.GB28181_TALK, sendRtpInfo.getReceiveStream());
|
||||
if (streamReady) {
|
||||
log.warn("[语音对讲] 进行中: {}", channel.getDeviceId());
|
||||
event.call("语音对讲进行中");
|
||||
@ -1647,7 +1630,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
String path = "snap";
|
||||
// 请求截图
|
||||
log.info("[请求截图]: " + fileName);
|
||||
mediaServerService.getSnap(mediaServer, MediaApp.GB28181, inviteInfo.getStreamInfo().getStream(), 15, 1, path, fileName);
|
||||
mediaServerService.getSnap(mediaServer, MediaStreamUtil.RTP_APP, inviteInfo.getStreamInfo().getStream(), 15, 1, path, fileName);
|
||||
File snapFile = new File(path + File.separator + fileName);
|
||||
if (snapFile.exists()) {
|
||||
errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapFile.getAbsoluteFile());
|
||||
@ -1697,7 +1680,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
String path = "snap";
|
||||
// 请求截图
|
||||
log.info("[请求截图]: 返回byte数组" );
|
||||
byte[] snapByteArray = mediaServerService.getSnap(mediaServer, MediaApp.GB28181, inviteInfo.getStreamInfo().getStream(), 15, 1, path, null);
|
||||
byte[] snapByteArray = mediaServerService.getSnap(mediaServer, MediaStreamUtil.RTP_APP, inviteInfo.getStreamInfo().getStream(), 15, 1, path, null);
|
||||
if (snapByteArray != null) {
|
||||
errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapByteArray);
|
||||
}else {
|
||||
@ -1711,7 +1694,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
if (code == InviteErrorCode.SUCCESS.getCode()) {
|
||||
InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getGbId());
|
||||
if (inviteInfoForPlay != null && inviteInfoForPlay.getStreamInfo() != null) {
|
||||
byte[] snapByteArray = mediaServerService.getSnap(data.getMediaServer(), MediaApp.GB28181, data.getStream(), 15, 1, null, null);
|
||||
byte[] snapByteArray = mediaServerService.getSnap(data.getMediaServer(), MediaStreamUtil.RTP_APP, data.getStream(), 15, 1, null, null);
|
||||
errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapByteArray);
|
||||
}else {
|
||||
errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null);
|
||||
@ -1729,6 +1712,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
if (!userSetting.getServerId().equals(device.getServerId())) {
|
||||
redisRpcPlayService.stop(device.getServerId(), type, channel.getId(), stream);
|
||||
}else {
|
||||
log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId());
|
||||
InviteInfo inviteInfo = inviteStreamService.getInviteInfo(type, channel.getId(), stream);
|
||||
if (inviteInfo == null) {
|
||||
if (type == InviteSessionType.PLAY) {
|
||||
@ -1739,8 +1723,8 @@ public class PlayServiceImpl implements IPlayService {
|
||||
inviteStreamService.removeInviteInfo(inviteInfo);
|
||||
if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
|
||||
try {
|
||||
log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId());
|
||||
cmder.streamByeCmd(device, channel.getDeviceId(), MediaApp.GB28181, inviteInfo.getStream(), null, null);
|
||||
log.info("[停止点播/回放/下载] 成功 {}/{}", device.getDeviceId(), channel.getDeviceId());
|
||||
cmder.streamByeCmd(device, channel.getDeviceId(), MediaStreamUtil.RTP_APP, inviteInfo.getStream(), null, null);
|
||||
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
|
||||
log.error("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage());
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
|
||||
@ -1751,7 +1735,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
deviceChannelService.stopPlay(channel.getId());
|
||||
}
|
||||
if (inviteInfo.getStreamInfo() != null) {
|
||||
receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), MediaApp.GB28181, stream);
|
||||
receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), MediaStreamUtil.RTP_APP, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1773,7 +1757,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
|
||||
try {
|
||||
log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId());
|
||||
cmder.streamByeCmd(device, channel.getDeviceId(), MediaApp.GB28181, inviteInfo.getStream(), null, null);
|
||||
cmder.streamByeCmd(device, channel.getDeviceId(), MediaStreamUtil.RTP_APP, inviteInfo.getStream(), null, null);
|
||||
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
|
||||
log.warn("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage());
|
||||
}
|
||||
@ -1783,7 +1767,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
deviceChannelService.stopPlay(channel.getId());
|
||||
}
|
||||
if (inviteInfo.getStreamInfo() != null) {
|
||||
receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), MediaApp.GB28181, inviteInfo.getStream());
|
||||
receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), MediaStreamUtil.RTP_APP, inviteInfo.getStream());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -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.StreamInfo;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
||||
@ -215,12 +215,8 @@ public class SIPCommander implements ISIPCommander {
|
||||
if (device == null) {
|
||||
return;
|
||||
}
|
||||
String sdpIp;
|
||||
if (!ObjectUtils.isEmpty(device.getSdpIp())) {
|
||||
sdpIp = device.getSdpIp();
|
||||
}else {
|
||||
sdpIp = mediaServerItem.getSdpIp();
|
||||
}
|
||||
String sdpIp = !ObjectUtils.isEmpty(device.getSdpIp()) ? device.getSdpIp() : mediaServerItem.getSdpIp();
|
||||
|
||||
StringBuffer content = new StringBuffer(200);
|
||||
content.append("v=0\r\n");
|
||||
content.append("o=" + device.getDeviceId() + " 0 0 IN IP4 " + sdpIp + "\r\n");
|
||||
@ -282,22 +278,22 @@ public class SIPCommander implements ISIPCommander {
|
||||
// f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
|
||||
// content.append("f=v/2/6/25/1/4000a/6/8/1" + "\r\n"); // 未发现支持此特性的设备
|
||||
|
||||
Request request = headerProvider.createInviteRequest(device, channel.getDeviceId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
|
||||
sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream());
|
||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrcToRelease());
|
||||
errorEvent.response(e);
|
||||
}), e -> {
|
||||
ResponseEvent responseEvent = (ResponseEvent) e.event;
|
||||
SIPResponse response = (SIPResponse) responseEvent.getResponse();
|
||||
String callId = response.getCallIdHeader().getCallId();
|
||||
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(),
|
||||
callId,ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response,
|
||||
InviteSessionType.PLAY);
|
||||
ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc());
|
||||
sessionManager.put(ssrcTransaction);
|
||||
okEvent.response(e);
|
||||
}, timeout);
|
||||
Request request = headerProvider.createInviteRequest(device, channel.getDeviceId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
|
||||
sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream());
|
||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrcToRelease());
|
||||
errorEvent.response(e);
|
||||
}), e -> {
|
||||
ResponseEvent responseEvent = (ResponseEvent) e.event;
|
||||
SIPResponse response = (SIPResponse) responseEvent.getResponse();
|
||||
String callId = response.getCallIdHeader().getCallId();
|
||||
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(),
|
||||
callId,ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response,
|
||||
InviteSessionType.PLAY);
|
||||
ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc());
|
||||
sessionManager.put(ssrcTransaction);
|
||||
okEvent.response(e);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -385,17 +381,17 @@ public class SIPCommander implements ISIPCommander {
|
||||
|
||||
Request request = headerProvider.createPlaybackInviteRequest(device, channel.getDeviceId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
|
||||
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
|
||||
ResponseEvent responseEvent = (ResponseEvent) event.event;
|
||||
SIPResponse response = (SIPResponse) responseEvent.getResponse();
|
||||
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(),
|
||||
channel.getId(), sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),
|
||||
device.getTransport()).getCallId(), ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInfo.getSsrc(),
|
||||
mediaServerItem.getId(), response, InviteSessionType.PLAYBACK);
|
||||
ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc());
|
||||
sessionManager.put(ssrcTransaction);
|
||||
okEvent.response(event);
|
||||
}, timeout);
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
|
||||
ResponseEvent responseEvent = (ResponseEvent) event.event;
|
||||
SIPResponse response = (SIPResponse) responseEvent.getResponse();
|
||||
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(),
|
||||
channel.getId(), sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),
|
||||
device.getTransport()).getCallId(), ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInfo.getSsrc(),
|
||||
mediaServerItem.getId(), response, InviteSessionType.PLAYBACK);
|
||||
ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc());
|
||||
sessionManager.put(ssrcTransaction);
|
||||
okEvent.response(event);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -478,18 +474,18 @@ public class SIPCommander implements ISIPCommander {
|
||||
CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
|
||||
Request request = headerProvider.createPlaybackInviteRequest(device, channel.getDeviceId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
|
||||
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
|
||||
ResponseEvent responseEvent = (ResponseEvent) event.event;
|
||||
SIPResponse response = (SIPResponse) responseEvent.getResponse();
|
||||
String contentString =new String(response.getRawContent());
|
||||
String ssrc = SipUtils.getSsrcFromSdp(contentString);
|
||||
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(),
|
||||
response.getCallIdHeader().getCallId(), ssrcInfo.getApp(), ssrcInfo.getStream(), ssrc,
|
||||
mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);
|
||||
ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc());
|
||||
sessionManager.put(ssrcTransaction);
|
||||
okEvent.response(event);
|
||||
}, timeout);
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
|
||||
ResponseEvent responseEvent = (ResponseEvent) event.event;
|
||||
SIPResponse response = (SIPResponse) responseEvent.getResponse();
|
||||
String contentString =new String(response.getRawContent());
|
||||
String ssrc = SipUtils.getSsrcFromSdp(contentString);
|
||||
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(),
|
||||
response.getCallIdHeader().getCallId(), ssrcInfo.getApp(), ssrcInfo.getStream(), ssrc,
|
||||
mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);
|
||||
ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc());
|
||||
sessionManager.put(ssrcTransaction);
|
||||
okEvent.response(event);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -509,7 +505,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
|
||||
log.info("[语音喊话] {} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.getPort());
|
||||
Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaApp.GB28181, stream, mediaServerItem.getId());
|
||||
Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaStreamUtil.RTP_APP, stream, mediaServerItem.getId());
|
||||
subscribe.addSubscribe(hook, (hookData) -> {
|
||||
if (event != null) {
|
||||
event.response(hookData);
|
||||
@ -519,7 +515,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
|
||||
CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
|
||||
callIdHeader.setCallId(callId);
|
||||
Hook publishHook = Hook.getInstance(HookType.on_publish, MediaApp.GB28181, stream, mediaServerItem.getId());
|
||||
Hook publishHook = Hook.getInstance(HookType.on_publish, MediaStreamUtil.RTP_APP, stream, mediaServerItem.getId());
|
||||
subscribe.addSubscribe(publishHook, (hookData) -> {
|
||||
if (eventForPush != null) {
|
||||
eventForPush.response(hookData);
|
||||
@ -543,21 +539,21 @@ public class SIPCommander implements ISIPCommander {
|
||||
// f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
|
||||
content.append("f=v/////a/1/8/1" + "\r\n");
|
||||
|
||||
Request request = headerProvider.createInviteRequest(device, channel.getDeviceId(), content.toString(),
|
||||
SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sendRtpItem.getSsrc(), callIdHeader);
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
|
||||
sessionManager.removeByStream(sendRtpItem.getApp(), sendRtpItem.getStream());
|
||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrcToRelease());
|
||||
errorEvent.response(e);
|
||||
}), e -> {
|
||||
// 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
|
||||
ResponseEvent responseEvent = (ResponseEvent) e.event;
|
||||
SIPResponse response = (SIPResponse) responseEvent.getResponse();
|
||||
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());
|
||||
sessionManager.put(ssrcTransaction);
|
||||
okEvent.response(e);
|
||||
}, timeout);
|
||||
Request request = headerProvider.createInviteRequest(device, channel.getDeviceId(), content.toString(),
|
||||
SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sendRtpItem.getSsrc(), callIdHeader);
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
|
||||
sessionManager.removeByStream(sendRtpItem.getApp(), sendRtpItem.getStream());
|
||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrcToRelease());
|
||||
errorEvent.response(e);
|
||||
}), e -> {
|
||||
// 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
|
||||
ResponseEvent responseEvent = (ResponseEvent) e.event;
|
||||
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.setAllocatedSsrc(sendRtpItem.getAllocatedSsrc());
|
||||
sessionManager.put(ssrcTransaction);
|
||||
okEvent.response(e);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1396,7 +1392,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
@Override
|
||||
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(MediaApp.GB28181, stream);
|
||||
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(MediaStreamUtil.RTP_APP, stream);
|
||||
if (ssrcTransaction == null) {
|
||||
log.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), stream);
|
||||
return;
|
||||
|
||||
@ -695,7 +695,7 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastInviteCmd(Platform platform, CommonGBChannel channel,String sourceId, MediaServer mediaServerItem,
|
||||
public void broadcastInviteCmd(Platform platform, CommonGBChannel channel,String sourceId, MediaServer mediaServer,
|
||||
SSRCInfo ssrcInfo, SipSubscribe.Event okEvent,
|
||||
SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException {
|
||||
String stream = ssrcInfo.getStream();
|
||||
@ -704,8 +704,8 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
||||
String sdpIp = mediaServerItem.getSdpIp();
|
||||
log.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServer.getId(), mediaServer.getIp(), ssrcInfo.getPort());
|
||||
String sdpIp = mediaServer.getSdpIp();
|
||||
|
||||
StringBuffer content = new StringBuffer(200);
|
||||
content.append("v=0\r\n");
|
||||
@ -744,13 +744,13 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
|
||||
callIdHeader);
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> {
|
||||
sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream());
|
||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrcToRelease());
|
||||
mediaServerService.releaseSsrc(mediaServer.getId(), ssrcInfo.getSsrcToRelease());
|
||||
errorEvent.response(e);
|
||||
}), e -> {
|
||||
ResponseEvent responseEvent = (ResponseEvent) e.event;
|
||||
SIPResponse response = (SIPResponse) responseEvent.getResponse();
|
||||
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForPlatform(platform.getServerGBId(), channel.getGbId(),
|
||||
callIdHeader.getCallId(), ssrcInfo.getApp(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.BROADCAST);
|
||||
callIdHeader.getCallId(), ssrcInfo.getApp(), stream, ssrcInfo.getSsrc(), mediaServer.getId(), response, InviteSessionType.BROADCAST);
|
||||
ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc());
|
||||
sessionManager.put(ssrcTransaction);
|
||||
okEvent.response(e);
|
||||
|
||||
@ -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.InviteSessionType;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.service.*;
|
||||
import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager;
|
||||
@ -99,7 +99,7 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
|
||||
playService.stop(inviteInfo);
|
||||
}
|
||||
// 去除监听流注销自动停止下载的监听
|
||||
Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaApp.GB28181, ssrcTransaction.getStream(), ssrcTransaction.getMediaServerId());
|
||||
Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaStreamUtil.RTP_APP, ssrcTransaction.getStream(), ssrcTransaction.getMediaServerId());
|
||||
subscribe.removeSubscribe(hook);
|
||||
if (ssrcTransaction.getPlatformId() != null) {
|
||||
// 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定
|
||||
|
||||
@ -15,4 +15,6 @@ public class JT1078Config {
|
||||
private Integer port;
|
||||
|
||||
private String password;
|
||||
|
||||
private Boolean record = false;
|
||||
}
|
||||
|
||||
@ -12,8 +12,6 @@ import java.util.List;
|
||||
|
||||
public interface Ijt1078PlayService {
|
||||
|
||||
JTMediaStreamType checkStreamFromJt(String stream);
|
||||
|
||||
void play(String phoneNumber, Integer channelId, int type, CommonCallback<WVPResult<StreamInfo>> callback);
|
||||
|
||||
void playback(String phoneNumber, Integer channelId, String startTime, String endTime, Integer type,
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -3,13 +3,14 @@ package com.genersoft.iot.vmp.jt1078.service.impl;
|
||||
import com.genersoft.iot.vmp.common.CommonCallback;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
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.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.jt1078.bean.*;
|
||||
import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template;
|
||||
import com.genersoft.iot.vmp.jt1078.config.JT1078Config;
|
||||
import com.genersoft.iot.vmp.jt1078.proc.request.J1205;
|
||||
import com.genersoft.iot.vmp.jt1078.proc.response.*;
|
||||
import com.genersoft.iot.vmp.jt1078.service.Ijt1078PlayService;
|
||||
@ -30,13 +31,13 @@ import com.genersoft.iot.vmp.service.ISendRtpServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||
import com.genersoft.iot.vmp.service.bean.RTPServerParam;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.utils.MediaServerUtils;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
@ -54,8 +55,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
@Slf4j
|
||||
public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
|
||||
public static final String talkApp = "jt_talk";
|
||||
|
||||
@Autowired
|
||||
private ISendRtpServerService sendRtpServerService;
|
||||
|
||||
@ -83,13 +82,16 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
|
||||
@Autowired
|
||||
private JT1078Config jt1078Config;
|
||||
|
||||
/**
|
||||
* 流到来的处理
|
||||
*/
|
||||
@Async
|
||||
@EventListener
|
||||
public void onApplicationEvent(MediaArrivalEvent event) {
|
||||
if (event.getApp().equals(talkApp) && event.getStream().endsWith("_talk")) {
|
||||
if (MediaStreamUtil.JT_TALK.equals(event.getApp()) && event.getStream().endsWith("_talk")) {
|
||||
// 收到对JT讲的流
|
||||
if (event.getStream().indexOf("_") <= 0) {
|
||||
log.info("[JT-对讲流到来] 流格式有误,stream应该为jt_[phoneNumber]_[channelId]_talk");
|
||||
@ -130,7 +132,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
if (!userSetting.getAutoApplyPlay()) {
|
||||
return;
|
||||
}
|
||||
JTMediaStreamType jtMediaStreamType = checkStreamFromJt(event.getStream());
|
||||
JTMediaStreamType jtMediaStreamType = checkStreamFromJt(event.getApp(), event.getStream());
|
||||
if (jtMediaStreamType == null){
|
||||
return;
|
||||
}
|
||||
@ -164,17 +166,15 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
/**
|
||||
* 校验流是否是属于部标的
|
||||
*/
|
||||
@Override
|
||||
public JTMediaStreamType checkStreamFromJt(String stream) {
|
||||
if (!stream.startsWith("jt_")) {
|
||||
private JTMediaStreamType checkStreamFromJt(String app, String stream) {
|
||||
if (!MediaStreamUtil.isJT1078(app, stream)) {
|
||||
return null;
|
||||
}
|
||||
String[] streamParamArray = stream.split("_");
|
||||
if (streamParamArray.length == 3) {
|
||||
if (MediaStreamUtil.isJT1078Play(app, stream)) {
|
||||
return JTMediaStreamType.PLAY;
|
||||
}else if (streamParamArray.length == 5) {
|
||||
}else if (MediaStreamUtil.isJT1078Playback(app, stream)) {
|
||||
return JTMediaStreamType.PLAYBACK;
|
||||
}else if (streamParamArray.length == 4) {
|
||||
}else if (MediaStreamUtil.isJT1078Talk(app, stream)) {
|
||||
return JTMediaStreamType.TALK;
|
||||
}else {
|
||||
return null;
|
||||
@ -200,7 +200,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
private void play(JTDevice device, JTChannel channel, int type, CommonCallback<WVPResult<StreamInfo>> callback) {
|
||||
String phoneNumber = device.getPhoneNumber();
|
||||
int channelId = channel.getChannelId();
|
||||
String stream = phoneNumber + "_" + channelId;
|
||||
String finalStream = MediaStreamUtil.getJTPlayStreamId(phoneNumber, channelId);
|
||||
// 检查流是否已经存在,存在则返回
|
||||
String playKey = VideoManagerConstants.INVITE_INFO_1078_PLAY + phoneNumber + ":" + channelId;
|
||||
List<CommonCallback<WVPResult<StreamInfo>>> errorCallbacks = inviteErrorCallbackMap.computeIfAbsent(playKey, k -> new ArrayList<>());
|
||||
@ -210,7 +210,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
MediaServer mediaServer = streamInfo.getMediaServer();
|
||||
if (mediaServer != null) {
|
||||
// 查询流是否存在,不存在则删除缓存数据
|
||||
MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, MediaApp.JT1078, streamInfo.getStream());
|
||||
MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, MediaStreamUtil.RTP_APP, streamInfo.getStream());
|
||||
if (mediaInfo != null) {
|
||||
log.info("[JT-点播] 点播已经存在,直接返回, phoneNumber: {}, channelId: {}", phoneNumber, channelId);
|
||||
for (CommonCallback<WVPResult<StreamInfo>> errorCallback : errorCallbacks) {
|
||||
@ -235,17 +235,29 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
}
|
||||
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.setMediaServer(mediaServer);
|
||||
rtpServerParam.setApp(MediaApp.JT1078);
|
||||
rtpServerParam.setStreamId(stream);
|
||||
rtpServerParam.setApp(MediaStreamUtil.RTP_APP);
|
||||
rtpServerParam.setStreamId(finalStream);
|
||||
rtpServerParam.setPort(0);
|
||||
rtpServerParam.setTcpMode(1); // 1 表示tcp被动
|
||||
rtpServerParam.setOnlyAuto(false);
|
||||
rtpServerParam.setDisableAudio(!channel.isHasAudio());
|
||||
|
||||
int port = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, hookData) -> {
|
||||
int port = receiveRtpServerService.openCommonRTPServer(rtpServerParam, (code, msg, hookData) -> {
|
||||
|
||||
if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) {
|
||||
// hook响应
|
||||
@ -264,8 +276,8 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
String path = "snap";
|
||||
String fileName = phoneNumber + "_" + channelId + ".jpg";
|
||||
// 请求截图
|
||||
log.info("[请求截图]: " + fileName);
|
||||
mediaServerService.getSnap(mediaServer, MediaApp.JT1078, stream, 15, 1, path, fileName);
|
||||
log.info("[请求截图]: {}", fileName);
|
||||
mediaServerService.getSnap(mediaServer, MediaStreamUtil.RTP_APP, finalStream, 15, 1, path, fileName);
|
||||
}else {
|
||||
if (callback != null) {
|
||||
callback.run(WVPResult.fail(code, msg));
|
||||
@ -282,6 +294,8 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
stopPlay(phoneNumber, channelId);
|
||||
return;
|
||||
}
|
||||
// 补充鉴权参数
|
||||
receiveRtpServerService.addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), jt1078Config.getRecord(), null);
|
||||
|
||||
log.info("[JT-点播] phoneNumber: {}, channelId: {},IP: {}, 端口: {}", phoneNumber, channelId, mediaServer.getSdpIp(), port);
|
||||
J9101 j9101 = new J9101();
|
||||
@ -295,7 +309,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
}
|
||||
|
||||
public StreamInfo onPublishHandler(MediaServer mediaServerItem, HookData hookData, String phoneNumber, Integer channelId) {
|
||||
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, MediaApp.JT1078, hookData.getStream(), hookData.getMediaInfo(), null);
|
||||
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, MediaStreamUtil.RTP_APP, hookData.getStream(), hookData.getMediaInfo(), null);
|
||||
streamInfo.setDeviceId(phoneNumber);
|
||||
streamInfo.setChannelId(channelId);
|
||||
return streamInfo;
|
||||
@ -438,8 +452,8 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
redisTemplate.delete(playbackKey);
|
||||
}
|
||||
|
||||
String app = MediaApp.JT1078;
|
||||
String stream = String.format("%s_%s_%s_%s", phoneNumber, channelId,
|
||||
String app = MediaStreamUtil.RTP_APP;
|
||||
String finalStream = MediaStreamUtil.getJTPlaybackStreamId(phoneNumber, channelId,
|
||||
DateUtil.yyyy_MM_dd_HH_mm_ssToUrl(startTime), DateUtil.yyyy_MM_dd_HH_mm_ssToUrl(endTime));
|
||||
MediaServer mediaServer;
|
||||
if (org.springframework.util.ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) {
|
||||
@ -453,18 +467,28 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
}
|
||||
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.setMediaServer(mediaServer);
|
||||
rtpServerParam.setApp(MediaApp.JT1078);
|
||||
rtpServerParam.setStreamId(stream);
|
||||
rtpServerParam.setApp(MediaStreamUtil.RTP_APP);
|
||||
rtpServerParam.setStreamId(finalStream);
|
||||
rtpServerParam.setPort(0);
|
||||
rtpServerParam.setTcpMode(1); // 1 表示tcp被动
|
||||
rtpServerParam.setOnlyAuto(false);
|
||||
rtpServerParam.setDisableAudio(!channel.isHasAudio());
|
||||
|
||||
int port = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, hookData) -> {
|
||||
int port = receiveRtpServerService.openCommonRTPServer(rtpServerParam, (code, msg, hookData) -> {
|
||||
|
||||
if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) {
|
||||
// hook 响应
|
||||
@ -484,10 +508,14 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
errorCallback.run(new WVPResult<>(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(),
|
||||
InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null));
|
||||
}
|
||||
receiveRtpServerService.closeRTPServer(mediaServer, app, stream);
|
||||
receiveRtpServerService.closeRTPServer(mediaServer, app, finalStream);
|
||||
}
|
||||
});
|
||||
log.info("[JT-回放] logInfo: {}, 端口: {}", logInfo, port);
|
||||
|
||||
// 补充鉴权参数
|
||||
receiveRtpServerService.addAuthenticateInfo(streamId, streamReplace, !channel.isHasAudio(), jt1078Config.getRecord(), null);
|
||||
|
||||
J9201 j9201 = new J9201();
|
||||
j9201.setChannel(channelId);
|
||||
j9201.setIp(mediaServer.getSdpIp());
|
||||
@ -595,7 +623,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
JTDevice device = jt1078Service.getDevice(phoneNumber);
|
||||
Assert.notNull(device, "部标设备不存在");
|
||||
|
||||
String stream = "jt_" + phoneNumber + "_" + channelId + "_talk";
|
||||
String stream = MediaStreamUtil.getJTTalkStreamId(phoneNumber, channelId);
|
||||
|
||||
MediaServer mediaServer;
|
||||
if (org.springframework.util.ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) {
|
||||
@ -605,9 +633,9 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
}
|
||||
|
||||
// 检查待发送的流是否存在,
|
||||
MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, talkApp, stream);
|
||||
MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, MediaStreamUtil.JT_TALK, stream);
|
||||
Assert.isNull(mediaInfo, "对讲已经存在");
|
||||
return mediaServerService.getStreamInfoByAppAndStream(mediaServer, talkApp, stream, null, null, null, false);
|
||||
return mediaServerService.getStreamInfoByAppAndStream(mediaServer, MediaStreamUtil.JT_TALK, stream, null, null, null, false);
|
||||
|
||||
}
|
||||
private void sendTalk(JTDevice device, Integer channelId, MediaServer mediaServer, String app, String stream) {
|
||||
@ -618,17 +646,17 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
|
||||
}
|
||||
|
||||
String phoneNumber = device.getPhoneNumber();
|
||||
|
||||
String receiveStream = MediaStreamUtil.getJTTalkReceiveStreamId(phoneNumber, channelId);
|
||||
// 开启收流端口, zlm发送1078的rtp流需要将ssrc字段设置为 imei_channel格式
|
||||
String ssrc = device.getPhoneNumber() + "_" + channelId;
|
||||
SendRtpInfo sendRtpInfo = sendRtpServerService.createSendRtpInfo(mediaServer, null, null, ssrc, phoneNumber, talkApp, stream, channelId, true, false);
|
||||
SendRtpInfo sendRtpInfo = sendRtpServerService.createSendRtpInfo(mediaServer, null, null, ssrc, phoneNumber, MediaStreamUtil.JT_TALK, stream, channelId, true, false);
|
||||
sendRtpInfo.setTcpActive(true);
|
||||
sendRtpInfo.setUsePs(false);
|
||||
sendRtpInfo.setOnlyAudio(true);
|
||||
sendRtpInfo.setReceiveStream(stream + "_talk");
|
||||
sendRtpInfo.setReceiveStream(receiveStream);
|
||||
|
||||
// 设置hook监听
|
||||
Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaApp.JT1078, sendRtpInfo.getReceiveStream(), mediaServer.getId());
|
||||
Hook hook = Hook.getInstance(HookType.on_media_arrival, MediaStreamUtil.RTP_APP, sendRtpInfo.getReceiveStream(), mediaServer.getId());
|
||||
subscribe.addSubscribe(hook, (hookData) -> {
|
||||
log.info("[JT-对讲] 对讲连接建立, phoneNumber: {}, channelId: {}", phoneNumber, channelId);
|
||||
subscribe.removeSubscribe(hook);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.genersoft.iot.vmp.media.abl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
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());
|
||||
try {
|
||||
if (MediaApp.GB28181.equals(param.getApp())) {
|
||||
if (MediaStreamUtil.RTP_APP.equals(param.getApp())) {
|
||||
return HookResult.SUCCESS();
|
||||
}
|
||||
MediaRtpServerTimeoutEvent event = new MediaRtpServerTimeoutEvent(this);
|
||||
MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||
if (mediaServerItem != null) {
|
||||
event.setMediaServer(mediaServerItem);
|
||||
event.setApp(MediaApp.GB28181);
|
||||
event.setApp(MediaStreamUtil.RTP_APP);
|
||||
applicationEventPublisher.publishEvent(event);
|
||||
}
|
||||
}catch (Exception e) {
|
||||
|
||||
@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.common.CommonCallback;
|
||||
import com.genersoft.iot.vmp.common.InviteInfo;
|
||||
import com.genersoft.iot.vmp.common.InviteSessionType;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
@ -248,7 +248,7 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService {
|
||||
|
||||
streamInfoResult.setMediaInfo(mediaInfo);
|
||||
|
||||
if (!MediaApp.GB28181_BROADCAST.equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) {
|
||||
if (!MediaStreamUtil.GB28181_BROADCAST.equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) {
|
||||
String newStream = stream + "_" + mediaServer.getTranscodeSuffix();
|
||||
mediaServer.setTranscodeSuffix(null);
|
||||
StreamInfo transcodeStreamInfo = getStreamInfoByAppAndStream(mediaServer, app, newStream, null, addr, callId, isPlay);
|
||||
|
||||
@ -1,59 +1,16 @@
|
||||
package com.genersoft.iot.vmp.media.bean;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ResultForOnPublish {
|
||||
|
||||
private boolean enable_audio;
|
||||
private boolean enable_mp4;
|
||||
private int mp4_max_second;
|
||||
private Boolean enable_audio;
|
||||
private Boolean enable_mp4;
|
||||
private Integer mp4_max_second;
|
||||
private String mp4_save_path;
|
||||
private String stream_replace;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
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());
|
||||
|
||||
// 查找对应的上级推流,发送停止
|
||||
if (!MediaApp.GB28181.equals(param.getApp())) {
|
||||
if (!MediaStreamUtil.RTP_APP.equals(param.getApp())) {
|
||||
return HookResult.SUCCESS();
|
||||
}
|
||||
try {
|
||||
@ -294,7 +294,7 @@ public class ZLMHttpHookListener {
|
||||
MediaServer mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
|
||||
if (mediaServerItem != null) {
|
||||
event.setMediaServer(mediaServerItem);
|
||||
event.setApp(MediaApp.GB28181);
|
||||
event.setApp(MediaStreamUtil.RTP_APP);
|
||||
applicationEventPublisher.publishEvent(event);
|
||||
}
|
||||
}catch (Exception e) {
|
||||
|
||||
@ -5,7 +5,7 @@ import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.CommonCallback;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
|
||||
@ -516,7 +516,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
|
||||
|
||||
@Override
|
||||
public void loadMP4File(MediaServer mediaServer, String app, String stream, String filePath, String fileName, ErrorCallback<StreamInfo> callback) {
|
||||
String buildApp = "mp4_record";
|
||||
String buildApp = MediaStreamUtil.LOAD_MP4_APP;
|
||||
String buildStream = app + "_" + stream + "_" + fileName + "_" + RandomStringUtils.randomAlphabetic(6).toLowerCase();
|
||||
|
||||
Hook hook = Hook.getInstance(HookType.on_media_arrival, buildApp, buildStream, mediaServer.getServerId());
|
||||
@ -539,7 +539,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
|
||||
|
||||
@Override
|
||||
public void loadMP4FileForDate(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback<StreamInfo> callback) {
|
||||
String buildApp = "mp4_record";
|
||||
String buildApp = MediaStreamUtil.LOAD_MP4_APP;
|
||||
String buildStream = app + "_" + stream + "_" + date;
|
||||
MediaInfo mediaInfo = getMediaInfo(mediaServer, buildApp, buildStream);
|
||||
if (mediaInfo != null) {
|
||||
@ -681,7 +681,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
|
||||
|
||||
streamInfoResult.setMediaInfo(mediaInfo);
|
||||
|
||||
if (!MediaApp.GB28181_BROADCAST.equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) {
|
||||
if (!MediaStreamUtil.GB28181_BROADCAST.equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) {
|
||||
String newStream = stream + "_" + mediaServer.getTranscodeSuffix();
|
||||
mediaServer.setTranscodeSuffix(null);
|
||||
StreamInfo transcodeStreamInfo = getStreamInfoByAppAndStream(mediaServer, app, newStream, null, addr, callId, isPlay);
|
||||
|
||||
@ -211,6 +211,16 @@ public class ZLMMediaServerStatusManager {
|
||||
String key = "zlm-keepalive-" + mediaServer.getId();
|
||||
dynamicTask.startDelay(key, ()->{
|
||||
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);
|
||||
offlineZlmPrimaryMap.put(mediaServer.getId(), mediaServer);
|
||||
offlineZlmTimeMap.put(mediaServer.getId(), System.currentTimeMillis());
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
package com.genersoft.iot.vmp.media.zlm.dto.hook;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class HookResult {
|
||||
|
||||
private int code;
|
||||
@ -22,19 +27,4 @@ public class HookResult {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,9 +8,9 @@ import lombok.Setter;
|
||||
@Getter
|
||||
public class HookResultForOnPublish extends HookResult{
|
||||
|
||||
private boolean enable_audio;
|
||||
private boolean enable_mp4;
|
||||
private int mp4_max_second;
|
||||
private Boolean enable_audio;
|
||||
private Boolean enable_mp4;
|
||||
private Integer mp4_max_second;
|
||||
private String mp4_save_path;
|
||||
private String stream_replace;
|
||||
private Integer modify_stamp;
|
||||
@ -24,8 +24,8 @@ public class HookResultForOnPublish extends HookResult{
|
||||
|
||||
public static HookResultForOnPublish getInstance(ResultForOnPublish resultForOnPublish){
|
||||
HookResultForOnPublish successResult = new HookResultForOnPublish(0, "success");
|
||||
successResult.setEnable_audio(resultForOnPublish.isEnable_audio());
|
||||
successResult.setEnable_mp4(resultForOnPublish.isEnable_mp4());
|
||||
successResult.setEnable_audio(resultForOnPublish.getEnable_audio());
|
||||
successResult.setEnable_mp4(resultForOnPublish.getEnable_mp4());
|
||||
successResult.setModify_stamp(resultForOnPublish.getModify_stamp());
|
||||
successResult.setStream_replace(resultForOnPublish.getStream_replace());
|
||||
successResult.setMp4_max_second(resultForOnPublish.getMp4_max_second());
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.OpenRTPServerResult;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
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.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.service.bean.RTPServerParam;
|
||||
@ -14,9 +14,29 @@ public interface IReceiveRtpServerService {
|
||||
boolean playback, boolean ssrcCheck, boolean onlyAuto, boolean disableAuto,
|
||||
ErrorCallback<OpenRTPServerResult> callback);
|
||||
|
||||
int openRTPServer(RTPServerParam rtpServerParam, ErrorCallback<HookData> callback);
|
||||
SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel,
|
||||
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 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);
|
||||
}
|
||||
|
||||
@ -9,13 +9,13 @@ public class SSRCInfo {
|
||||
private String ssrc;
|
||||
private String allocatedSsrc;
|
||||
private String app;
|
||||
private String Stream;
|
||||
private String stream;
|
||||
|
||||
public SSRCInfo(int port, String ssrc, String app, String stream) {
|
||||
this.port = port;
|
||||
this.ssrc = ssrc;
|
||||
this.app = app;
|
||||
this.Stream = stream;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public String getSsrcToRelease() {
|
||||
|
||||
@ -1,89 +1,53 @@
|
||||
package com.genersoft.iot.vmp.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.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
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.gb28181.service.ISourceOtherService;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||
import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
|
||||
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.ISendRtpServerService;
|
||||
import com.genersoft.iot.vmp.service.IUserService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
|
||||
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.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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 java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MediaServiceImpl implements IMediaService {
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
private final IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private IStreamProxyService streamProxyService;
|
||||
private final IStreamProxyService streamProxyService;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
private final UserSetting userSetting;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<Object, Object> redisTemplate;
|
||||
private final IUserService userService;
|
||||
|
||||
@Autowired
|
||||
private IUserService userService;
|
||||
private final IReceiveRtpServerService receiveRtpServerService;
|
||||
|
||||
@Autowired
|
||||
private IInviteStreamService inviteStreamService;
|
||||
private final IRecordPlanService recordPlanService;
|
||||
|
||||
@Autowired
|
||||
private IDeviceChannelService deviceChannelService;
|
||||
private final Map<String, ISourceOtherService> sourceOtherServiceMap;
|
||||
|
||||
@Autowired
|
||||
private SipInviteSessionManager sessionManager;
|
||||
|
||||
@Autowired
|
||||
private Ijt1078Service ijt1078Service;
|
||||
|
||||
@Autowired
|
||||
private Ijt1078PlayService jt1078PlayService;
|
||||
|
||||
@Autowired
|
||||
private ISendRtpServerService sendRtpServerService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IRecordPlanService recordPlanService;
|
||||
|
||||
@Override
|
||||
public boolean authenticatePlay(String app, String stream, String callId) {
|
||||
if (app == null || stream == null) {
|
||||
return false;
|
||||
}
|
||||
if (MediaApp.GB28181.equals(app)) {
|
||||
if (MediaStreamUtil.RTP_APP.equals(app)) {
|
||||
return true;
|
||||
}
|
||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
|
||||
@ -95,29 +59,24 @@ public class MediaServiceImpl implements IMediaService {
|
||||
|
||||
@Override
|
||||
public ResultForOnPublish authenticatePublish(MediaServer mediaServer, String app, String stream, String params) {
|
||||
// 推流鉴权的处理
|
||||
if (!MediaApp.GB28181.equals(app) && !MediaApp.JT1078.equals(app) ) {
|
||||
if (MediaApp.GB28181_TALK.equals(app) && stream.endsWith("_talk")) {
|
||||
ResultForOnPublish result = new ResultForOnPublish();
|
||||
|
||||
if (MediaStreamUtil.RTP_APP.equals(app)) {
|
||||
return receiveRtpServerService.getAuthenticateInfo(stream);
|
||||
}else {
|
||||
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_audio(true);
|
||||
return result;
|
||||
}
|
||||
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();
|
||||
if (MediaStreamUtil.LOAD_MP4_APP.equals(app) ) {
|
||||
result.setEnable_mp4(false);
|
||||
result.setEnable_audio(true);
|
||||
return result;
|
||||
}
|
||||
StreamProxy streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, stream);
|
||||
if (streamProxyItem != null) {
|
||||
ResultForOnPublish result = new ResultForOnPublish();
|
||||
result.setEnable_audio(streamProxyItem.isEnableAudio());
|
||||
result.setEnable_mp4(streamProxyItem.isEnableMp4());
|
||||
return result;
|
||||
@ -150,152 +109,46 @@ public class MediaServiceImpl implements IMediaService {
|
||||
// 鉴权通过
|
||||
redisCatchStorage.updateStreamAuthorityInfo(app, stream, streamAuthorityInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
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
|
||||
public boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema) {
|
||||
boolean result = false;
|
||||
if (recordPlanService.recording(app, stream) != null) {
|
||||
return false;
|
||||
}
|
||||
// 国标类型的流
|
||||
if (MediaApp.GB28181.equals(app)) {
|
||||
result = userSetting.getStreamOnDemand();
|
||||
// 国标流, 点播/录像回放/录像下载
|
||||
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, stream);
|
||||
if (inviteInfo != 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 result;
|
||||
}
|
||||
}else if (MediaApp.JT1078.equals(app)) {
|
||||
// 判断是否是1078播放类型
|
||||
JTMediaStreamType jtMediaStreamType = ijt1078Service.checkStreamFromJt(stream);
|
||||
if (jtMediaStreamType != null) {
|
||||
String[] streamParamArray = stream.split("_");
|
||||
if (jtMediaStreamType.equals(JTMediaStreamType.PLAY)) {
|
||||
jt1078PlayService.stopPlay(streamParamArray[0], Integer.parseInt(streamParamArray[1]));
|
||||
}else if (jtMediaStreamType.equals(JTMediaStreamType.PLAYBACK)) {
|
||||
jt1078PlayService.stopPlayback(streamParamArray[0], Integer.parseInt(streamParamArray[1]));
|
||||
}
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}else if (MediaApp.GB28181_TALK.equals(app) || MediaApp.GB28181_BROADCAST.equals(app)) {
|
||||
return false;
|
||||
} else if ("mp4_record".equals(app)) {
|
||||
if (MediaStreamUtil.LOAD_MP4_APP.equals(app)) {
|
||||
// mp4点播流, 无人观看不关闭
|
||||
return true;
|
||||
} else {
|
||||
// 非国标流 推流/拉流代理
|
||||
// 拉流代理
|
||||
StreamProxy streamProxy = streamProxyService.getStreamProxyByAppAndStream(app, stream);
|
||||
if (streamProxy != null) {
|
||||
if (streamProxy.isEnableDisableNoneReader()) {
|
||||
// 无人观看停用
|
||||
// 修改数据
|
||||
streamProxyService.stopByAppAndStream(app, stream);
|
||||
return true;
|
||||
} else {
|
||||
// 无人观看不做处理
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ISourceOtherService sourceOtherService : sourceOtherServiceMap.values()) {
|
||||
try {
|
||||
Boolean result = sourceOtherService.closeStreamOnNoneReader(mediaServerId, app, stream, schema);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}else {
|
||||
return false;
|
||||
}catch (Exception e) {
|
||||
log.error("调用其他服务关闭无人观看流失败, app={}, stream={}, schema={}", app, stream, schema, e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
// 拉流代理
|
||||
StreamProxy streamProxy = streamProxyService.getStreamProxyByAppAndStream(app, stream);
|
||||
if (streamProxy != null) {
|
||||
if (streamProxy.isEnableDisableNoneReader()) {
|
||||
// 无人观看停用
|
||||
// 修改数据
|
||||
streamProxyService.stopByAppAndStream(app, stream);
|
||||
return true;
|
||||
} else {
|
||||
// 无人观看不做处理
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return userSetting.getStreamOnDemand();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
package com.genersoft.iot.vmp.service.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.OpenRTPServerResult;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
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.ResultForOnPublish;
|
||||
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.HookSubscribe;
|
||||
@ -19,13 +20,16 @@ import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||
import com.genersoft.iot.vmp.service.bean.RTPServerParam;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -49,7 +53,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
|
||||
private HookSubscribe subscribe;
|
||||
|
||||
@Autowired
|
||||
private SipInviteSessionManager sessionManager;
|
||||
private RedisTemplate<Object, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 流到来的处理
|
||||
@ -101,12 +105,12 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
|
||||
log.warn("[openRTPServer] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验");
|
||||
}
|
||||
|
||||
SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaApp.GB28181, streamId);
|
||||
SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId);
|
||||
if (presetSSRC == null) {
|
||||
ssrcInfo.setAllocatedSsrc(ssrc);
|
||||
}
|
||||
RTPServerParam rtpServerParam = new RTPServerParam(mediaServer, MediaApp.GB28181, streamId, ssrcCheck ? Long.parseLong(ssrc): 0L, null, onlyAuto, disableAuto, false, tcpMode);
|
||||
int rtpServerPort = openRTPServer(rtpServerParam, ((code, msg, data) -> {
|
||||
RTPServerParam rtpServerParam = new RTPServerParam(mediaServer, MediaStreamUtil.RTP_APP, streamId, ssrcCheck ? Long.parseLong(ssrc): 0L, null, onlyAuto, disableAuto, false, tcpMode);
|
||||
int rtpServerPort = openCommonRTPServer(rtpServerParam, ((code, msg, data) -> {
|
||||
if (code == InviteErrorCode.SUCCESS.getCode()) {
|
||||
OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult();
|
||||
openRTPServerResult.setHookData(data);
|
||||
@ -124,11 +128,203 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
|
||||
}
|
||||
}));
|
||||
ssrcInfo.setPort(rtpServerPort);
|
||||
return new SSRCInfo(rtpServerPort, ssrc, MediaApp.GB28181, streamId);
|
||||
return new SSRCInfo(rtpServerPort, ssrc, MediaStreamUtil.RTP_APP, streamId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int openRTPServer(RTPServerParam rtpServerParam, ErrorCallback<HookData> callback) {
|
||||
public SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel,
|
||||
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) {
|
||||
log.warn("[开启RTP收流] 失败,回调为NULL");
|
||||
return -1;
|
||||
@ -181,7 +377,10 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
|
||||
if (dynamicTask.contains(timeOutTaskKey)) {
|
||||
dynamicTask.stop(timeOutTaskKey);
|
||||
}
|
||||
mediaServerService.closeRTPServer(mediaServer, app, stream);
|
||||
if (mediaServer.isRtpEnable()) {
|
||||
mediaServerService.closeRTPServer(mediaServer, app, stream);
|
||||
}
|
||||
mediaServerService.closeStreams(mediaServer, app, stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -192,4 +391,39 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.streamProxy.service.impl;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
|
||||
@ -104,7 +104,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
@Async
|
||||
@EventListener
|
||||
public void onApplicationEvent(MediaNotFoundEvent event) {
|
||||
if (MediaApp.isKeywords(event.getApp())) {
|
||||
if (MediaStreamUtil.isKeywords(event.getApp())) {
|
||||
return;
|
||||
}
|
||||
// 拉流代理
|
||||
|
||||
@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.streamPush.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
|
||||
@ -102,7 +102,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
|
||||
updatePushStatus(streamPushInDb);
|
||||
}
|
||||
// 冗余数据,自己系统中自用
|
||||
if (!MediaApp.GB28181_BROADCAST.equals(event.getApp()) && !MediaApp.GB28181_TALK.equals(event.getApp())) {
|
||||
if (!MediaStreamUtil.GB28181_BROADCAST.equals(event.getApp()) && !MediaStreamUtil.GB28181_TALK.equals(event.getApp())) {
|
||||
redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event.getMediaInfo());
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.genersoft.iot.vmp.vmanager.ps;
|
||||
|
||||
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.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
@ -16,7 +16,6 @@ import com.genersoft.iot.vmp.service.IReceiveRtpServerService;
|
||||
import com.genersoft.iot.vmp.service.ISendRtpServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||
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.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
|
||||
@ -102,12 +101,12 @@ public class PsController {
|
||||
|
||||
RTPServerParam rtpServerParam = new RTPServerParam();
|
||||
rtpServerParam.setMediaServer(mediaServer);
|
||||
rtpServerParam.setApp(MediaApp.GB28181);
|
||||
rtpServerParam.setApp(MediaStreamUtil.RTP_APP);
|
||||
rtpServerParam.setStreamId(stream);
|
||||
rtpServerParam.setSsrc(ssrcInt);
|
||||
rtpServerParam.setTcpMode(tcpMode);
|
||||
|
||||
int rtpServerPort = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> {
|
||||
int rtpServerPort = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> {
|
||||
if (callBack == null) {
|
||||
return;
|
||||
}
|
||||
@ -134,6 +133,10 @@ public class PsController {
|
||||
if (rtpServerPort == 0) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败");
|
||||
}
|
||||
|
||||
// 补充鉴权参数
|
||||
receiveRtpServerService.addAuthenticateInfo(stream, null, false, false, null);
|
||||
|
||||
OtherPsSendInfo otherPsSendInfo = new OtherPsSendInfo();
|
||||
otherPsSendInfo.setReceiveIp(mediaServer.getSdpIp());
|
||||
otherPsSendInfo.setReceivePort(rtpServerPort);
|
||||
@ -163,7 +166,7 @@ public class PsController {
|
||||
public void closeRtpServer(String stream) {
|
||||
log.info("[第三方PS服务对接->关闭收流] stream->{}", stream);
|
||||
MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
|
||||
receiveRtpServerService.closeRTPServer(mediaServerItem, MediaApp.GB28181, stream);
|
||||
receiveRtpServerService.closeRTPServer(mediaServerItem, MediaStreamUtil.RTP_APP, stream);
|
||||
String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_*_" + stream;
|
||||
List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey);
|
||||
if (!scan.isEmpty()) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.genersoft.iot.vmp.vmanager.rtp;
|
||||
|
||||
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.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
@ -16,7 +16,6 @@ import com.genersoft.iot.vmp.service.IReceiveRtpServerService;
|
||||
import com.genersoft.iot.vmp.service.ISendRtpServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||
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.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
|
||||
@ -102,13 +101,13 @@ public class RtpController {
|
||||
|
||||
RTPServerParam rtpServerParam = new RTPServerParam();
|
||||
rtpServerParam.setMediaServer(mediaServer);
|
||||
rtpServerParam.setApp(MediaApp.GB28181);
|
||||
rtpServerParam.setApp(MediaStreamUtil.RTP_APP);
|
||||
rtpServerParam.setStreamId(stream);
|
||||
rtpServerParam.setSsrc(ssrcInt);
|
||||
rtpServerParam.setTcpMode(tcpMode);
|
||||
|
||||
|
||||
int rtpServerPortForVideo = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> {
|
||||
int rtpServerPortForVideo = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> {
|
||||
if (callBack == null) {
|
||||
return;
|
||||
}
|
||||
@ -127,16 +126,21 @@ public class RtpController {
|
||||
log.info("[开启收流和获取发流信息] 视频流收流失败,callId->{},stream->{}", callId, stream);
|
||||
}
|
||||
}));
|
||||
|
||||
// 补充鉴权参数
|
||||
receiveRtpServerService.addAuthenticateInfo(stream, null, false, false, null);
|
||||
rtpServerParam.setStreamId(stream + "_a");
|
||||
|
||||
int rtpServerPortForAudio = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> {
|
||||
int rtpServerPortForAudio = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> {
|
||||
if (code == InviteErrorCode.SUCCESS.getCode()) {
|
||||
log.info("[开启收流和获取发流信息] 音频流收流成功,callId->{},stream->{}", callId, stream);
|
||||
}else {
|
||||
log.info("[开启收流和获取发流信息] 音频流收流失败,callId->{},stream->{}", callId, stream);
|
||||
}
|
||||
}));
|
||||
|
||||
// 补充鉴权参数
|
||||
receiveRtpServerService.addAuthenticateInfo(rtpServerParam.getStreamId(), null, true, false, null);
|
||||
|
||||
if (rtpServerPortForVideo == 0 || rtpServerPortForAudio == 0) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败");
|
||||
}
|
||||
@ -174,8 +178,8 @@ public class RtpController {
|
||||
public void closeRtpServer(String stream) {
|
||||
log.info("[第三方服务对接->关闭收流] stream->{}", stream);
|
||||
MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
|
||||
receiveRtpServerService.closeRTPServer(mediaServerItem, MediaApp.GB28181, stream);
|
||||
receiveRtpServerService.closeRTPServer(mediaServerItem, MediaApp.GB28181, stream+ "_a");
|
||||
receiveRtpServerService.closeRTPServer(mediaServerItem, MediaStreamUtil.RTP_APP, stream);
|
||||
receiveRtpServerService.closeRTPServer(mediaServerItem, MediaStreamUtil.RTP_APP, stream+ "_a");
|
||||
String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_*_" + stream;
|
||||
List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey);
|
||||
if (scan.size() > 0) {
|
||||
|
||||
@ -4,7 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.InviteInfo;
|
||||
import com.genersoft.iot.vmp.common.InviteSessionType;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaApp;
|
||||
import com.genersoft.iot.vmp.common.enums.MediaStreamUtil;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
@ -247,7 +247,7 @@ public class ApiStreamController {
|
||||
}
|
||||
|
||||
try {
|
||||
cmder.streamByeCmd(device, code, MediaApp.GB28181, inviteInfo.getStream(), null, null);
|
||||
cmder.streamByeCmd(device, code, MediaStreamUtil.RTP_APP, inviteInfo.getStream(), null, null);
|
||||
} catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("error","发送BYE失败:" + e.getMessage());
|
||||
|
||||
@ -11,8 +11,9 @@
|
||||
<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/config.js"></script>
|
||||
<script type="text/javascript" src="./static/js/h265web2/h265web.js"></script>
|
||||
<!-- <script type="text/javascript" src="./static/js/h265web/missile.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>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
|
||||
@ -157,7 +157,7 @@ export function startPlayback(params) {
|
||||
const { phoneNumber, channelId, startTime, endTime, type, rate, playbackType, playbackSpeed } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/jt1078/playback/start/',
|
||||
url: '/api/jt1078/playback/start',
|
||||
params: {
|
||||
phoneNumber: phoneNumber,
|
||||
channelId: channelId,
|
||||
@ -204,7 +204,7 @@ export function stopPlayback(params) {
|
||||
const { phoneNumber, channelId, streamId } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/jt1078/playback/stop/',
|
||||
url: '/api/jt1078/playback/stop',
|
||||
params: {
|
||||
phoneNumber: phoneNumber,
|
||||
channelId: channelId,
|
||||
|
||||
@ -134,48 +134,34 @@ export default {
|
||||
},
|
||||
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 options = {}
|
||||
h265webPlayer[this._uid] = new window.new265webjs(url, Object.assign(
|
||||
{
|
||||
player: 'glplayer', // 播放器容器id
|
||||
width: this.playerWidth,
|
||||
height: this.playerHeight,
|
||||
token: token,
|
||||
extInfo: {
|
||||
coreProbePart: 0.4,
|
||||
probeSize: 8192,
|
||||
ignoreAudio: this.hasAudio === null ? 0 : (this.hasAudio ? 0 : 1)
|
||||
}
|
||||
},
|
||||
options
|
||||
))
|
||||
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.onReadyShowDone = () => {
|
||||
// 准备好显示了,尝试自动播放
|
||||
const result = h265web.play()
|
||||
this.playing = result
|
||||
this.playerLoading = false
|
||||
}
|
||||
h265web.onLoadFinish = () => {
|
||||
this.loaded = true
|
||||
// 可以获取mediaInfo
|
||||
@ -185,7 +171,7 @@ export default {
|
||||
h265web.onPlayTime = (videoPTS) => {
|
||||
this.$emit('playTimeChange', videoPTS * 1000)
|
||||
}
|
||||
// h265web.do()
|
||||
h265web.do()
|
||||
},
|
||||
screenshot: function() {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
@ -193,7 +179,7 @@ export default {
|
||||
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
|
||||
h265webPlayer[this._uid].snapshot(canvas) // snapshot to canvas
|
||||
|
||||
// 下载截图
|
||||
const link = document.createElement('a')
|
||||
@ -227,14 +213,14 @@ export default {
|
||||
unPause: function() {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
h265webPlayer[this._uid].play()
|
||||
this.playing = true
|
||||
this.playing = h265webPlayer[this._uid].isPlaying()
|
||||
}
|
||||
this.err = ''
|
||||
},
|
||||
pause: function() {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
h265webPlayer[this._uid].pause()
|
||||
this.playing = false
|
||||
this.playing = h265webPlayer[this._uid].isPlaying()
|
||||
}
|
||||
this.err = ''
|
||||
},
|
||||
|
||||
344
web/src/views/common/h265web.vue.bak
Normal file
344
web/src/views/common/h265web.vue.bak
Normal file
@ -0,0 +1,344 @@
|
||||
<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>
|
||||
@ -13,10 +13,10 @@
|
||||
<div id="shared" style="margin-right: 20px;">
|
||||
<el-form ref="passwordForm" :rules="rules" status-icon label-width="80px">
|
||||
<el-form-item label="新密码" prop="newPassword">
|
||||
<el-input v-model="newPassword" autocomplete="off" />
|
||||
<el-input v-model="newPassword" autocomplete="off" type="password" />
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPassword">
|
||||
<el-input v-model="confirmPassword" autocomplete="off" />
|
||||
<el-input v-model="confirmPassword" autocomplete="off" type="password" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
@ -88,6 +88,14 @@ export default {
|
||||
}
|
||||
},
|
||||
onSubmit: function() {
|
||||
if (this.newPassword !== this.confirmPassword) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '两次输入密码不一致!',
|
||||
type: 'error'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$store.dispatch('user/changePasswordForAdmin', {
|
||||
password: this.newPassword,
|
||||
userId: this.form.id
|
||||
|
||||
@ -65,16 +65,22 @@ export default {
|
||||
.then(data => {
|
||||
this.listChangeCallback()
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
.catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$store.dispatch('jtDevice/add', this.form)
|
||||
.then(data => {
|
||||
this.listChangeCallback()
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
.catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user