Compare commits

...

11 Commits

Author SHA1 Message Date
阿斌
3105bc2cb0
Pre Merge pull request !36 from 阿斌/N/A 2026-04-16 04:39:45 +00:00
lin
0984e8f1ed 移除SipSendFailEvent 2026-04-16 12:39:30 +08:00
lin
4a3a19379f 修复命名错误 2026-04-15 19:24:53 +08:00
lin
37a4cb0ad7 修复命名错误 2026-04-15 19:17:52 +08:00
lin
a1441016f7 无人观看流程处理与接入设备类型解耦 2026-04-15 19:12:38 +08:00
lin
f961d6fc8d 优化无人观看判断逻辑 2026-04-15 12:58:52 +08:00
lin
1e5ae10571 调整流处理逻辑以支持单端口收流 2026-04-15 00:31:49 +08:00
lin
3e162ea358 优化错误处理,回滚播放器版本,重构RTP服务器接口以区分不同的接口功能,优化参数数量 2026-04-14 18:11:14 +08:00
lin
ab3d0da115 更新MediaStreamUtil中的应用常量,统一使用RTP_APP替代GB28181,调整相关逻辑以支持单端口收流 2026-04-13 23:05:14 +08:00
lin
e88d26b1e9 重命名MediaApp为MediaStreamUtil并更新相关引用 2026-04-13 18:09:51 +08:00
阿斌
da98101aac
update src/main/resources/civilCode.csv.
行政规划错误。江苏南通海门市,修改为海门区,浙江杭州删除下城区、江干区,新增钱塘区,临平区

Signed-off-by: 阿斌 <38912748@qq.com>
2024-12-15 08:58:42 +00:00
47 changed files with 1168 additions and 639 deletions

View File

@ -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;
}

View File

@ -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";

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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]};
}
}
}

View File

@ -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自动关流无泄露

View File

@ -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());

View File

@ -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;
}
}

View File

@ -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<>();

View File

@ -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%schannelId%sdownloadSpeed%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;

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -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);

View File

@ -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="));

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.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;

View File

@ -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);

View File

@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify
import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.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进行上下级绑定

View File

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

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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) {

View File

@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.common.CommonCallback;
import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.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);

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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);

View File

@ -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());

View File

@ -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;
}
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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() {

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
// 拉流代理

View File

@ -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());
}

View File

@ -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()) {

View File

@ -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) {

View File

@ -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());

View File

@ -861,7 +861,7 @@
320623,如东县,3206
320681,启东市,3206
320682,如皋市,3206
320684,海门,3206
320684,海门,3206
320685,海安市,3206
3207,连云港市,32
320703,连云区,3207
@ -918,8 +918,6 @@
33,浙江省,
3301,杭州市,33
330102,上城区,3301
330103,下城区,3301
330104,江干区,3301
330105,拱墅区,3301
330106,西湖区,3301
330108,滨江区,3301
@ -927,6 +925,8 @@
330110,余杭区,3301
330111,富阳区,3301
330112,临安区,3301
330113,临平区,3301
330114,钱塘区,3301
330122,桐庐县,3301
330127,淳安县,3301
330182,建德市,3301

1 编号 名称 上级
861 320623 如东县 3206
862 320681 启东市 3206
863 320682 如皋市 3206
864 320684 海门市 海门区 3206
865 320685 海安市 3206
866 3207 连云港市 32
867 320703 连云区 3207
918 33 浙江省
919 3301 杭州市 33
920 330102 上城区 3301
330103 下城区 3301
330104 江干区 3301
921 330105 拱墅区 3301
922 330106 西湖区 3301
923 330108 滨江区 3301
925 330110 余杭区 3301
926 330111 富阳区 3301
927 330112 临安区 3301
928 330113 临平区 3301
929 330114 钱塘区 3301
930 330122 桐庐县 3301
931 330127 淳安县 3301
932 330182 建德市 3301

View File

@ -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>

View File

@ -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,

View File

@ -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 = ''
},

View 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>

View File

@ -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
})
})
}
},