Merge remote-tracking branch 'github/wvp-28181-2.0' into dev-2.6.9_整理
# Conflicts: # src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
This commit is contained in:
commit
be75aa7a68
@ -1,6 +1,9 @@
|
|||||||
package com.genersoft.iot.vmp.conf;
|
package com.genersoft.iot.vmp.conf;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -42,6 +45,9 @@ public class DynamicTask {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public void startCron(String key, Runnable task, int cycleForCatalog) {
|
public void startCron(String key, Runnable task, int cycleForCatalog) {
|
||||||
|
if(ObjectUtils.isEmpty(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ScheduledFuture<?> future = futureMap.get(key);
|
ScheduledFuture<?> future = futureMap.get(key);
|
||||||
if (future != null) {
|
if (future != null) {
|
||||||
if (future.isCancelled()) {
|
if (future.isCancelled()) {
|
||||||
@ -70,6 +76,9 @@ public class DynamicTask {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public void startDelay(String key, Runnable task, int delay) {
|
public void startDelay(String key, Runnable task, int delay) {
|
||||||
|
if(ObjectUtils.isEmpty(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
stop(key);
|
stop(key);
|
||||||
|
|
||||||
// 获取执行的时刻
|
// 获取执行的时刻
|
||||||
@ -96,9 +105,12 @@ public class DynamicTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean stop(String key) {
|
public boolean stop(String key) {
|
||||||
|
if(ObjectUtils.isEmpty(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
if (futureMap.get(key) != null && !futureMap.get(key).isCancelled() && !futureMap.get(key).isDone()) {
|
if (!ObjectUtils.isEmpty(futureMap.get(key)) && !futureMap.get(key).isCancelled() && !futureMap.get(key).isDone()) {
|
||||||
result = futureMap.get(key).cancel(false);
|
result = futureMap.get(key).cancel(true);
|
||||||
futureMap.remove(key);
|
futureMap.remove(key);
|
||||||
runnableMap.remove(key);
|
runnableMap.remove(key);
|
||||||
}
|
}
|
||||||
@ -106,6 +118,9 @@ public class DynamicTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(String key) {
|
public boolean contains(String key) {
|
||||||
|
if(ObjectUtils.isEmpty(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return futureMap.get(key) != null;
|
return futureMap.get(key) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +129,9 @@ public class DynamicTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Runnable get(String key) {
|
public Runnable get(String key) {
|
||||||
|
if(ObjectUtils.isEmpty(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return runnableMap.get(key);
|
return runnableMap.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ public class Device {
|
|||||||
* 是否开启ssrc校验,默认关闭,开启可以防止串流
|
* 是否开启ssrc校验,默认关闭,开启可以防止串流
|
||||||
*/
|
*/
|
||||||
@Schema(description = "是否开启ssrc校验,默认关闭,开启可以防止串流")
|
@Schema(description = "是否开启ssrc校验,默认关闭,开启可以防止串流")
|
||||||
private boolean ssrcCheck = true;
|
private boolean ssrcCheck = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 地理坐标系, 目前支持 WGS84,GCJ02
|
* 地理坐标系, 目前支持 WGS84,GCJ02
|
||||||
|
@ -166,6 +166,7 @@ public class SIPRequestHeaderPlarformProvider {
|
|||||||
|
|
||||||
public Request createMessageRequest(ParentPlatform parentPlatform, String content, SendRtpItem sendRtpItem) throws PeerUnavailableException, ParseException, InvalidArgumentException {
|
public Request createMessageRequest(ParentPlatform parentPlatform, String content, SendRtpItem sendRtpItem) throws PeerUnavailableException, ParseException, InvalidArgumentException {
|
||||||
CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(sendRtpItem.getCallId());
|
CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(sendRtpItem.getCallId());
|
||||||
|
callIdHeader.setCallId(sendRtpItem.getCallId());
|
||||||
return createMessageRequest(parentPlatform, content, sendRtpItem.getToTag(), SipUtils.getNewViaTag(), sendRtpItem.getFromTag(), callIdHeader);
|
return createMessageRequest(parentPlatform, content, sendRtpItem.getToTag(), SipUtils.getNewViaTag(), sendRtpItem.getFromTag(), callIdHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,9 +111,20 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
logger.warn("[收到ACK]:未找到通道({})的推流信息", channelId);
|
logger.warn("[收到ACK]:未找到通道({})的推流信息", channelId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// tcp主动时,此时是级联下级平台,在回复200ok时,本地已经请求zlm开启监听,跳过下面步骤
|
||||||
|
if (sendRtpItem.isTcpActive()) {
|
||||||
|
logger.info("收到ACK,rtp/{} TCP主动方式后续处理", sendRtpItem.getStreamId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
|
String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
|
||||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||||
logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
|
logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, 协议:{}",
|
||||||
|
sendRtpItem.getStreamId(),
|
||||||
|
sendRtpItem.getIp(),
|
||||||
|
sendRtpItem.getPort(),
|
||||||
|
sendRtpItem.getSsrc(),
|
||||||
|
sendRtpItem.isTcp()?(sendRtpItem.isTcpActive()?"TCP主动":"TCP被动"):"UDP"
|
||||||
|
);
|
||||||
Map<String, Object> param = new HashMap<>(12);
|
Map<String, Object> param = new HashMap<>(12);
|
||||||
param.put("vhost","__defaultVhost__");
|
param.put("vhost","__defaultVhost__");
|
||||||
param.put("app",sendRtpItem.getApp());
|
param.put("app",sendRtpItem.getApp());
|
||||||
@ -130,10 +141,6 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
// 开启rtcp保活
|
// 开启rtcp保活
|
||||||
param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
|
param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
|
||||||
}
|
}
|
||||||
// tcp主动时,此时是级联下级平台,在回复200ok时,本地已经请求zlm开启监听,跳过下面步骤
|
|
||||||
if (sendRtpItem.isTcpActive()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mediaInfo == null) {
|
if (mediaInfo == null) {
|
||||||
RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
|
RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
|
||||||
sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),
|
sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),
|
||||||
|
@ -138,7 +138,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
|||||||
logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId);
|
logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
logger.info("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
|
||||||
cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null);
|
cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null);
|
||||||
} catch (InvalidArgumentException | ParseException | SipException |
|
} catch (InvalidArgumentException | ParseException | SipException |
|
||||||
SsrcTransactionNotFoundException e) {
|
SsrcTransactionNotFoundException e) {
|
||||||
|
@ -33,7 +33,7 @@ import java.text.ParseException;
|
|||||||
public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
|
public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
|
||||||
|
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class);
|
||||||
private final static String cmdType = "Keepalive";
|
private final static String cmdType = "Keepalive";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -59,14 +59,19 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
|
|||||||
// 未注册的设备不做处理
|
// 未注册的设备不做处理
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.info("[收到心跳], device: {}", device.getDeviceId());
|
|
||||||
SIPRequest request = (SIPRequest) evt.getRequest();
|
SIPRequest request = (SIPRequest) evt.getRequest();
|
||||||
|
logger.info("[收到心跳], device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId());
|
||||||
|
|
||||||
// 回复200 OK
|
// 回复200 OK
|
||||||
try {
|
try {
|
||||||
responseAck(request, Response.OK);
|
responseAck(request, Response.OK);
|
||||||
} catch (SipException | InvalidArgumentException | ParseException e) {
|
} catch (SipException | InvalidArgumentException | ParseException e) {
|
||||||
logger.error("[命令发送失败] 心跳回复: {}", e.getMessage());
|
logger.error("[命令发送失败] 心跳回复: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
if (DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L){
|
||||||
|
logger.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress());
|
RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress());
|
||||||
if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) {
|
if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) {
|
||||||
@ -80,7 +85,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
|
|||||||
}else {
|
}else {
|
||||||
long lastTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(device.getKeepaliveTime());
|
long lastTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(device.getKeepaliveTime());
|
||||||
if (System.currentTimeMillis()/1000-lastTime > 10) {
|
if (System.currentTimeMillis()/1000-lastTime > 10) {
|
||||||
device.setKeepaliveIntervalTime(new Long(System.currentTimeMillis()/1000-lastTime).intValue());
|
device.setKeepaliveIntervalTime(Long.valueOf(System.currentTimeMillis()/1000-lastTime).intValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,6 +494,7 @@ public class ZLMHttpHookListener {
|
|||||||
Device device = deviceService.getDevice(inviteInfo.getDeviceId());
|
Device device = deviceService.getDevice(inviteInfo.getDeviceId());
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
try {
|
try {
|
||||||
|
// 多查询一次防止已经被处理了
|
||||||
InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),
|
InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),
|
||||||
inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
|
inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
|
@ -98,6 +98,9 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
|
|||||||
"_" + inviteInfo.getChannelId() +
|
"_" + inviteInfo.getChannelId() +
|
||||||
"_" + stream;
|
"_" + stream;
|
||||||
inviteInfoInDb.setStream(stream);
|
inviteInfoInDb.setStream(stream);
|
||||||
|
if (inviteInfoInDb.getSsrcInfo() != null) {
|
||||||
|
inviteInfoInDb.getSsrcInfo().setStream(stream);
|
||||||
|
}
|
||||||
redisTemplate.opsForValue().set(key, inviteInfoInDb);
|
redisTemplate.opsForValue().set(key, inviteInfoInDb);
|
||||||
return inviteInfoInDb;
|
return inviteInfoInDb;
|
||||||
}
|
}
|
||||||
|
@ -151,9 +151,14 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
|||||||
if (streamId == null) {
|
if (streamId == null) {
|
||||||
streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
|
streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
|
||||||
}
|
}
|
||||||
|
int ssrcCheckParam = 0;
|
||||||
|
if (ssrcCheck && tcpMode > 1) {
|
||||||
|
// 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验
|
||||||
|
logger.warn("[openRTPServer] TCP被动/TCP主动收流时,默认关闭ssrc检验");
|
||||||
|
}
|
||||||
int rtpServerPort;
|
int rtpServerPort;
|
||||||
if (mediaServerItem.isRtpEnable()) {
|
if (mediaServerItem.isRtpEnable()) {
|
||||||
rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port, reUsePort, tcpMode);
|
rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0)?Integer.parseInt(ssrc):0, port, reUsePort, tcpMode);
|
||||||
} else {
|
} else {
|
||||||
rtpServerPort = mediaServerItem.getRtpProxyPort();
|
rtpServerPort = mediaServerItem.getRtpProxyPort();
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,11 @@ import com.genersoft.iot.vmp.conf.exception.ServiceException;
|
|||||||
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||||
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||||
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
|
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
||||||
@ -34,10 +34,10 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
|||||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||||
|
import gov.nist.javax.sip.message.SIPResponse;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
@ -95,7 +95,6 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private VideoStreamSessionManager streamSession;
|
private VideoStreamSessionManager streamSession;
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IDeviceService deviceService;
|
private IDeviceService deviceService;
|
||||||
|
|
||||||
@ -108,25 +107,25 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ZlmHttpHookSubscribe subscribe;
|
private ZlmHttpHookSubscribe subscribe;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private SSRCFactory ssrcFactory;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisTemplate<Object, Object> redisTemplate;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback) {
|
public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback) {
|
||||||
if (mediaServerItem == null) {
|
if (mediaServerItem == null) {
|
||||||
|
logger.warn("[点播] 未找到可用的zlm deviceId: {},channelId:{}", deviceId, channelId);
|
||||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm");
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm");
|
||||||
}
|
}
|
||||||
|
|
||||||
Device device = redisCatchStorage.getDevice(deviceId);
|
Device device = redisCatchStorage.getDevice(deviceId);
|
||||||
|
if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE") && !mediaServerItem.isRtpEnable()) {
|
||||||
|
logger.warn("[点播] 单端口收流时不支持TCP主动方式收流 deviceId: {},channelId:{}", deviceId, channelId);
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "单端口收流时不支持TCP主动方式收流");
|
||||||
|
}
|
||||||
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
|
InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
|
||||||
if (inviteInfo != null ) {
|
if (inviteInfo != null ) {
|
||||||
if (inviteInfo.getStreamInfo() == null) {
|
if (inviteInfo.getStreamInfo() == null) {
|
||||||
// 点播发起了但是尚未成功, 仅注册回调等待结果即可
|
// 点播发起了但是尚未成功, 仅注册回调等待结果即可
|
||||||
inviteStreamService.once(InviteSessionType.PLAY, deviceId, channelId, null, callback);
|
inviteStreamService.once(InviteSessionType.PLAY, deviceId, channelId, null, callback);
|
||||||
|
logger.info("[点播开始] 已经请求中,等待结果, deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
|
||||||
return inviteInfo.getSsrcInfo();
|
return inviteInfo.getSsrcInfo();
|
||||||
}else {
|
}else {
|
||||||
StreamInfo streamInfo = inviteInfo.getStreamInfo();
|
StreamInfo streamInfo = inviteInfo.getStreamInfo();
|
||||||
@ -149,6 +148,7 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
InviteErrorCode.SUCCESS.getCode(),
|
InviteErrorCode.SUCCESS.getCode(),
|
||||||
InviteErrorCode.SUCCESS.getMsg(),
|
InviteErrorCode.SUCCESS.getMsg(),
|
||||||
streamInfo);
|
streamInfo);
|
||||||
|
logger.info("[点播已存在] 直接返回, deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
|
||||||
return inviteInfo.getSsrcInfo();
|
return inviteInfo.getSsrcInfo();
|
||||||
}else {
|
}else {
|
||||||
// 点播发起了但是尚未成功, 仅注册回调等待结果即可
|
// 点播发起了但是尚未成功, 仅注册回调等待结果即可
|
||||||
@ -171,7 +171,6 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
null);
|
null);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// TODO 记录点播的状态
|
|
||||||
play(mediaServerItem, ssrcInfo, device, channelId, callback);
|
play(mediaServerItem, ssrcInfo, device, channelId, callback);
|
||||||
return ssrcInfo;
|
return ssrcInfo;
|
||||||
}
|
}
|
||||||
@ -187,8 +186,8 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
null);
|
null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.info("[点播开始] deviceId: {}, channelId: {},码流类型:{}, 收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
|
logger.info("[点播开始] deviceId: {}, channelId: {},码流类型:{}, 收流端口: {}, STREAM:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
|
||||||
device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", ssrcInfo.getPort(),
|
device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", ssrcInfo.getPort(), ssrcInfo.getStream(),
|
||||||
device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
|
device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
|
||||||
//端口获取失败的ssrcInfo 没有必要发送点播指令
|
//端口获取失败的ssrcInfo 没有必要发送点播指令
|
||||||
if (ssrcInfo.getPort() <= 0) {
|
if (ssrcInfo.getPort() <= 0) {
|
||||||
@ -219,16 +218,6 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流",
|
device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流",
|
||||||
ssrcInfo.getPort(), ssrcInfo.getSsrc());
|
ssrcInfo.getPort(), ssrcInfo.getSsrc());
|
||||||
|
|
||||||
// 点播超时回复BYE 同时释放ssrc以及此次点播的资源
|
|
||||||
// InviteInfo inviteInfoForTimeout = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.play, device.getDeviceId(), channelId);
|
|
||||||
// if (inviteInfoForTimeout == null) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if (InviteSessionStatus.ok == inviteInfoForTimeout.getStatus() ) {
|
|
||||||
// // TODO 发送bye
|
|
||||||
// }else {
|
|
||||||
// // TODO 发送cancel
|
|
||||||
// }
|
|
||||||
callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
|
callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
|
||||||
inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
|
inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
|
||||||
InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
|
InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
|
||||||
@ -272,99 +261,10 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channelId,
|
logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channelId,
|
||||||
device.isSwitchPrimarySubStream() ? "辅码流" : "主码流");
|
device.isSwitchPrimarySubStream() ? "辅码流" : "主码流");
|
||||||
snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channelId, ssrcInfo.getStream());
|
snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channelId, ssrcInfo.getStream());
|
||||||
}, (event) -> {
|
}, (eventResult) -> {
|
||||||
inviteInfo.setStatus(InviteSessionStatus.ok);
|
// 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
|
||||||
|
InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId,
|
||||||
ResponseEvent responseEvent = (ResponseEvent) event.event;
|
timeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAY);
|
||||||
String contentString = new String(responseEvent.getResponse().getRawContent());
|
|
||||||
// 获取ssrc
|
|
||||||
int ssrcIndex = contentString.indexOf("y=");
|
|
||||||
// 检查是否有y字段
|
|
||||||
if (ssrcIndex >= 0) {
|
|
||||||
//ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
|
|
||||||
String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim();
|
|
||||||
// 查询到ssrc不一致且开启了ssrc校验则需要针对处理
|
|
||||||
if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
|
|
||||||
if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
|
|
||||||
tcpActiveHandler(device, channelId, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
|
|
||||||
if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
|
|
||||||
logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
|
|
||||||
// 释放ssrc
|
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
|
||||||
// 单端口模式streamId也有变化,重新设置监听即可
|
|
||||||
if (!mediaServerItem.isRtpEnable()) {
|
|
||||||
// 添加订阅
|
|
||||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
|
|
||||||
subscribe.removeSubscribe(hookSubscribe);
|
|
||||||
String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
|
|
||||||
hookSubscribe.getContent().put("stream", stream);
|
|
||||||
inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);
|
|
||||||
subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
|
|
||||||
logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);
|
|
||||||
dynamicTask.stop(timeOutTaskKey);
|
|
||||||
// hook响应
|
|
||||||
StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, hookParam, device.getDeviceId(), channelId);
|
|
||||||
if (streamInfo == null){
|
|
||||||
callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
|
|
||||||
InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
|
|
||||||
inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
|
|
||||||
InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
|
|
||||||
InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback.run(InviteErrorCode.SUCCESS.getCode(),
|
|
||||||
InviteErrorCode.SUCCESS.getMsg(), streamInfo);
|
|
||||||
inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
|
|
||||||
InviteErrorCode.SUCCESS.getCode(),
|
|
||||||
InviteErrorCode.SUCCESS.getMsg(),
|
|
||||||
streamInfo);
|
|
||||||
snapOnPlay(mediaServerItemInUse, device.getDeviceId(), channelId, stream);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新ssrc
|
|
||||||
Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
|
|
||||||
if (!result) {
|
|
||||||
try {
|
|
||||||
logger.warn("[点播] 更新ssrc失败,停止点播 {}/{}", device.getDeviceId(), channelId);
|
|
||||||
cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
|
|
||||||
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
|
|
||||||
logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamicTask.stop(timeOutTaskKey);
|
|
||||||
// 释放ssrc
|
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
|
||||||
|
|
||||||
streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
|
|
||||||
|
|
||||||
callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
|
|
||||||
"下级自定义了ssrc,重新设置收流信息失败", null);
|
|
||||||
inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
|
|
||||||
InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
|
|
||||||
"下级自定义了ssrc,重新设置收流信息失败", null);
|
|
||||||
|
|
||||||
}else {
|
|
||||||
if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) {
|
|
||||||
inviteStreamService.removeInviteInfo(inviteInfo);
|
|
||||||
}
|
|
||||||
ssrcInfo.setSsrc(ssrcInResponse);
|
|
||||||
inviteInfo.setSsrcInfo(ssrcInfo);
|
|
||||||
inviteInfo.setStream(ssrcInfo.getStream());
|
|
||||||
if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
|
|
||||||
tcpActiveHandler(device, channelId, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inviteStreamService.updateInviteInfo(inviteInfo);
|
|
||||||
}, (event) -> {
|
}, (event) -> {
|
||||||
dynamicTask.stop(timeOutTaskKey);
|
dynamicTask.stop(timeOutTaskKey);
|
||||||
mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
|
mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
|
||||||
@ -422,11 +322,11 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
|
logger.info("[TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
|
||||||
JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
|
JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
|
||||||
logger.info("[点播-TCP主动连接对方] 结果: {}", jsonObject);
|
logger.info("[TCP主动连接对方] 结果: {}", jsonObject);
|
||||||
} catch (SdpException e) {
|
} catch (SdpException e) {
|
||||||
logger.error("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
|
logger.error("[TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
|
||||||
dynamicTask.stop(timeOutTaskKey);
|
dynamicTask.stop(timeOutTaskKey);
|
||||||
mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
|
mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
|
||||||
// 释放ssrc
|
// 释放ssrc
|
||||||
@ -548,19 +448,23 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
String endTime, ErrorCallback<Object> callback) {
|
String endTime, ErrorCallback<Object> callback) {
|
||||||
Device device = storager.queryVideoDevice(deviceId);
|
Device device = storager.queryVideoDevice(deviceId);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
return;
|
logger.warn("[录像回放] 未找到设备 deviceId: {},channelId:{}", deviceId, channelId);
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到设备:" + deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
|
MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
|
||||||
|
if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE") && ! newMediaServerItem.isRtpEnable()) {
|
||||||
|
logger.warn("[录像回放] 单端口收流时不支持TCP主动方式收流 deviceId: {},channelId:{}", deviceId, channelId);
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "单端口收流时不支持TCP主动方式收流");
|
||||||
|
}
|
||||||
String stream = null;
|
String stream = null;
|
||||||
if (newMediaServerItem.isRtpEnable()) {
|
if (newMediaServerItem.isRtpEnable()) {
|
||||||
String startTimeStr = startTime.replace("-", "")
|
String startTimeStr = startTime.replace("-", "")
|
||||||
.replace(":", "")
|
.replace(":", "")
|
||||||
.replace(" ", "");
|
.replace(" ", "");
|
||||||
System.out.println(startTimeStr);
|
|
||||||
String endTimeTimeStr = endTime.replace("-", "")
|
String endTimeTimeStr = endTime.replace("-", "")
|
||||||
.replace(":", "")
|
.replace(":", "")
|
||||||
.replace(" ", "");
|
.replace(" ", "");
|
||||||
System.out.println(endTimeTimeStr);
|
|
||||||
stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr;
|
stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr;
|
||||||
}
|
}
|
||||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
|
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
|
||||||
@ -636,113 +540,13 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
try {
|
try {
|
||||||
cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime,
|
cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime,
|
||||||
hookEvent, eventResult -> {
|
hookEvent, eventResult -> {
|
||||||
inviteInfo.setStatus(InviteSessionStatus.ok);
|
// 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
|
||||||
ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
|
InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId,
|
||||||
String contentString = new String(responseEvent.getResponse().getRawContent());
|
playBackTimeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAYBACK);
|
||||||
// 获取ssrc
|
|
||||||
int ssrcIndex = contentString.indexOf("y=");
|
|
||||||
// 检查是否有y字段
|
|
||||||
if (ssrcIndex >= 0) {
|
|
||||||
//ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
|
|
||||||
String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
|
|
||||||
// 查询到ssrc不一致且开启了ssrc校验则需要针对处理
|
|
||||||
if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
|
|
||||||
if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
|
|
||||||
String substring = contentString.substring(0, contentString.indexOf("y="));
|
|
||||||
try {
|
|
||||||
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
|
|
||||||
int port = -1;
|
|
||||||
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
|
|
||||||
for (Object description : mediaDescriptions) {
|
|
||||||
MediaDescription mediaDescription = (MediaDescription) description;
|
|
||||||
Media media = mediaDescription.getMedia();
|
|
||||||
|
|
||||||
Vector mediaFormats = media.getMediaFormats(false);
|
|
||||||
if (mediaFormats.contains("96")) {
|
|
||||||
port = media.getMediaPort();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.info("[录像回放-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
|
|
||||||
JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
|
|
||||||
logger.info("[录像回放-TCP主动连接对方] 结果: {}", jsonObject);
|
|
||||||
} catch (SdpException e) {
|
|
||||||
logger.error("[录像回放-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
|
|
||||||
dynamicTask.stop(playBackTimeOutTaskKey);
|
|
||||||
mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
|
|
||||||
// 释放ssrc
|
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
|
||||||
|
|
||||||
streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
|
|
||||||
|
|
||||||
callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
|
|
||||||
InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
|
|
||||||
inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
|
|
||||||
InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
|
|
||||||
InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
logger.info("[录像回放] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
|
|
||||||
if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
|
|
||||||
logger.info("[录像回放] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
|
|
||||||
|
|
||||||
// 释放ssrc
|
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
|
||||||
|
|
||||||
// 单端口模式streamId也有变化,需要重新设置监听
|
|
||||||
if (!mediaServerItem.isRtpEnable()) {
|
|
||||||
// 添加订阅
|
|
||||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
|
|
||||||
subscribe.removeSubscribe(hookSubscribe);
|
|
||||||
String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
|
|
||||||
hookSubscribe.getContent().put("stream", stream);
|
|
||||||
inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);
|
|
||||||
subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
|
|
||||||
logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);
|
|
||||||
dynamicTask.stop(playBackTimeOutTaskKey);
|
|
||||||
// hook响应
|
|
||||||
hookEvent.response(mediaServerItemInUse, hookParam);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 更新ssrc
|
|
||||||
Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
|
|
||||||
if (!result) {
|
|
||||||
try {
|
|
||||||
logger.warn("[录像回放] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);
|
|
||||||
cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
|
|
||||||
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
|
|
||||||
logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamicTask.stop(playBackTimeOutTaskKey);
|
|
||||||
// 释放ssrc
|
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
|
||||||
|
|
||||||
streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
|
|
||||||
|
|
||||||
callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
|
|
||||||
"下级自定义了ssrc,重新设置收流信息失败", null);
|
|
||||||
|
|
||||||
}else {
|
|
||||||
if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) {
|
|
||||||
inviteStreamService.removeInviteInfo(inviteInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssrcInfo.setSsrc(ssrcInResponse);
|
|
||||||
inviteInfo.setSsrcInfo(ssrcInfo);
|
|
||||||
inviteInfo.setStream(ssrcInfo.getStream());
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inviteStreamService.updateInviteInfo(inviteInfo);
|
|
||||||
}, errorEvent);
|
}, errorEvent);
|
||||||
} catch (InvalidArgumentException | SipException | ParseException e) {
|
} catch (InvalidArgumentException | SipException | ParseException e) {
|
||||||
logger.error("[命令发送失败] 回放: {}", e.getMessage());
|
logger.error("[命令发送失败] 录像回放: {}", e.getMessage());
|
||||||
|
|
||||||
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();
|
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();
|
||||||
eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent;
|
eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent;
|
||||||
@ -753,6 +557,121 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void InviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, MediaServerItem mediaServerItem,
|
||||||
|
Device device, String channelId, String timeOutTaskKey, ErrorCallback<Object> callback,
|
||||||
|
InviteInfo inviteInfo, InviteSessionType inviteSessionType){
|
||||||
|
inviteInfo.setStatus(InviteSessionStatus.ok);
|
||||||
|
ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
|
||||||
|
String contentString = new String(responseEvent.getResponse().getRawContent());
|
||||||
|
String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString);
|
||||||
|
if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
|
||||||
|
// ssrc 一致
|
||||||
|
if (mediaServerItem.isRtpEnable()) {
|
||||||
|
// 多端口
|
||||||
|
if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
|
||||||
|
tcpActiveHandler(device, channelId, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
// 单端口
|
||||||
|
if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
|
||||||
|
logger.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
logger.info("[Invite 200OK] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
|
||||||
|
// ssrc 不一致
|
||||||
|
if (mediaServerItem.isRtpEnable()) {
|
||||||
|
// 多端口
|
||||||
|
if (device.isSsrcCheck()) {
|
||||||
|
// ssrc检验
|
||||||
|
// 更新ssrc
|
||||||
|
logger.info("[Invite 200OK] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
|
||||||
|
// 释放ssrc
|
||||||
|
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
||||||
|
Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
|
||||||
|
if (!result) {
|
||||||
|
try {
|
||||||
|
logger.warn("[Invite 200OK] 更新ssrc失败,停止点播 {}/{}", device.getDeviceId(), channelId);
|
||||||
|
cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
|
||||||
|
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
|
||||||
|
logger.error("[命令发送失败] 停止播放, 发送BYE: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicTask.stop(timeOutTaskKey);
|
||||||
|
// 释放ssrc
|
||||||
|
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
||||||
|
|
||||||
|
streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
|
||||||
|
|
||||||
|
callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
|
||||||
|
"下级自定义了ssrc,重新设置收流信息失败", null);
|
||||||
|
inviteStreamService.call(inviteSessionType, device.getDeviceId(), channelId, null,
|
||||||
|
InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
|
||||||
|
"下级自定义了ssrc,重新设置收流信息失败", null);
|
||||||
|
|
||||||
|
}else {
|
||||||
|
ssrcInfo.setSsrc(ssrcInResponse);
|
||||||
|
inviteInfo.setSsrcInfo(ssrcInfo);
|
||||||
|
inviteInfo.setStream(ssrcInfo.getStream());
|
||||||
|
if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
|
||||||
|
if (mediaServerItem.isRtpEnable()) {
|
||||||
|
tcpActiveHandler(device, channelId, contentString, mediaServerItem, timeOutTaskKey, ssrcInfo, callback);
|
||||||
|
}else {
|
||||||
|
logger.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inviteStreamService.updateInviteInfo(inviteInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if (ssrcInResponse != null) {
|
||||||
|
// 单端口
|
||||||
|
// 重新订阅流上线
|
||||||
|
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp",
|
||||||
|
ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
|
||||||
|
subscribe.removeSubscribe(hookSubscribe);
|
||||||
|
SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(inviteInfo.getDeviceId(),
|
||||||
|
inviteInfo.getChannelId(), null, inviteInfo.getStream());
|
||||||
|
streamSession.remove(inviteInfo.getDeviceId(),
|
||||||
|
inviteInfo.getChannelId(), inviteInfo.getStream());
|
||||||
|
|
||||||
|
String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
|
||||||
|
hookSubscribe.getContent().put("stream", stream);
|
||||||
|
|
||||||
|
inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);
|
||||||
|
streamSession.put(device.getDeviceId(), channelId, ssrcTransaction.getCallId(),
|
||||||
|
stream, ssrcInResponse, mediaServerItem.getId(), (SIPResponse) responseEvent.getResponse(), inviteSessionType);
|
||||||
|
subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
|
||||||
|
logger.info("[Invite 200OK] ssrc修正后收到订阅消息: " + hookParam);
|
||||||
|
dynamicTask.stop(timeOutTaskKey);
|
||||||
|
subscribe.removeSubscribe(hookSubscribe);
|
||||||
|
// hook响应
|
||||||
|
StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, hookParam, device.getDeviceId(), channelId);
|
||||||
|
if (streamInfo == null){
|
||||||
|
callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
|
||||||
|
InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
|
||||||
|
inviteStreamService.call(inviteSessionType, device.getDeviceId(), channelId, null,
|
||||||
|
InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
|
||||||
|
InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback.run(InviteErrorCode.SUCCESS.getCode(),
|
||||||
|
InviteErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||||
|
inviteStreamService.call(inviteSessionType, device.getDeviceId(), channelId, null,
|
||||||
|
InviteErrorCode.SUCCESS.getCode(),
|
||||||
|
InviteErrorCode.SUCCESS.getMsg(),
|
||||||
|
streamInfo);
|
||||||
|
if (inviteSessionType == InviteSessionType.PLAY) {
|
||||||
|
snapOnPlay(mediaServerItemInUse, device.getDeviceId(), channelId, stream);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) {
|
public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) {
|
||||||
@ -767,6 +686,7 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
null);
|
null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 录像下载不使用固定流地址,固定流地址会导致如果开始时间与结束时间一致时文件错误的叠加在一起
|
||||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
|
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
|
||||||
download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, callback);
|
download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, callback);
|
||||||
}
|
}
|
||||||
@ -835,108 +755,9 @@ public class PlayServiceImpl implements IPlayService {
|
|||||||
try {
|
try {
|
||||||
cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed,
|
cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed,
|
||||||
hookEvent, errorEvent, eventResult ->{
|
hookEvent, errorEvent, eventResult ->{
|
||||||
inviteInfo.setStatus(InviteSessionStatus.ok);
|
// 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
|
||||||
ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
|
InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId,
|
||||||
String contentString = new String(responseEvent.getResponse().getRawContent());
|
downLoadTimeOutTaskKey, callback, inviteInfo, InviteSessionType.DOWNLOAD);
|
||||||
// 获取ssrc
|
|
||||||
int ssrcIndex = contentString.indexOf("y=");
|
|
||||||
// 检查是否有y字段
|
|
||||||
if (ssrcIndex >= 0) {
|
|
||||||
//ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
|
|
||||||
String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
|
|
||||||
// 查询到ssrc不一致且开启了ssrc校验则需要针对处理
|
|
||||||
if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
|
|
||||||
if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
|
|
||||||
String substring = contentString.substring(0, contentString.indexOf("y="));
|
|
||||||
try {
|
|
||||||
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
|
|
||||||
int port = -1;
|
|
||||||
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
|
|
||||||
for (Object description : mediaDescriptions) {
|
|
||||||
MediaDescription mediaDescription = (MediaDescription) description;
|
|
||||||
Media media = mediaDescription.getMedia();
|
|
||||||
|
|
||||||
Vector mediaFormats = media.getMediaFormats(false);
|
|
||||||
if (mediaFormats.contains("96")) {
|
|
||||||
port = media.getMediaPort();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.info("[录像下载-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
|
|
||||||
JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
|
|
||||||
logger.info("[录像下载-TCP主动连接对方] 结果: {}", jsonObject);
|
|
||||||
} catch (SdpException e) {
|
|
||||||
logger.error("[录像下载-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
|
|
||||||
dynamicTask.stop(downLoadTimeOutTaskKey);
|
|
||||||
mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
|
|
||||||
// 释放ssrc
|
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
|
||||||
|
|
||||||
streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
|
|
||||||
|
|
||||||
callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
|
|
||||||
InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
|
|
||||||
inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
|
|
||||||
InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
|
|
||||||
InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
logger.info("[录像下载] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
|
|
||||||
if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
|
|
||||||
logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
|
|
||||||
|
|
||||||
// 释放ssrc
|
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
|
||||||
|
|
||||||
// 单端口模式streamId也有变化,需要重新设置监听
|
|
||||||
if (!mediaServerItem.isRtpEnable()) {
|
|
||||||
// 添加订阅
|
|
||||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
|
|
||||||
subscribe.removeSubscribe(hookSubscribe);
|
|
||||||
String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
|
|
||||||
hookSubscribe.getContent().put("stream", stream);
|
|
||||||
inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);
|
|
||||||
subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
|
|
||||||
logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);
|
|
||||||
dynamicTask.stop(downLoadTimeOutTaskKey);
|
|
||||||
hookEvent.response(mediaServerItemInUse, hookParam);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新ssrc
|
|
||||||
Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
|
|
||||||
if (!result) {
|
|
||||||
try {
|
|
||||||
logger.warn("[录像下载] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);
|
|
||||||
cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
|
|
||||||
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
|
|
||||||
logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamicTask.stop(downLoadTimeOutTaskKey);
|
|
||||||
// 释放ssrc
|
|
||||||
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
|
||||||
|
|
||||||
streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
|
|
||||||
|
|
||||||
callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
|
|
||||||
"下级自定义了ssrc,重新设置收流信息失败", null);
|
|
||||||
|
|
||||||
}else {
|
|
||||||
if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) {
|
|
||||||
inviteStreamService.removeInviteInfo(inviteInfo);
|
|
||||||
}
|
|
||||||
ssrcInfo.setSsrc(ssrcInResponse);
|
|
||||||
inviteInfo.setSsrcInfo(ssrcInfo);
|
|
||||||
inviteInfo.setStream(ssrcInfo.getStream());
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
logger.info("[录像下载] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inviteStreamService.updateInviteInfo(inviteInfo);
|
|
||||||
});
|
});
|
||||||
} catch (InvalidArgumentException | SipException | ParseException e) {
|
} catch (InvalidArgumentException | SipException | ParseException e) {
|
||||||
logger.error("[命令发送失败] 录像下载: {}", e.getMessage());
|
logger.error("[命令发送失败] 录像下载: {}", e.getMessage());
|
||||||
|
@ -7,6 +7,7 @@ import java.time.LocalDateTime;
|
|||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -106,4 +107,9 @@ public class DateUtil {
|
|||||||
LocalDateTime nowDateTime = LocalDateTime.now();
|
LocalDateTime nowDateTime = LocalDateTime.now();
|
||||||
return formatterISO8601.format(nowDateTime);
|
return formatterISO8601.format(nowDateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long getDifferenceForNow(String keepaliveTime) {
|
||||||
|
Instant beforeInstant = Instant.from(formatter.parse(keepaliveTime));
|
||||||
|
return ChronoUnit.MILLIS.between(beforeInstant, Instant.now());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ public class PlayController {
|
|||||||
wvpResult.setCode(ErrorCode.ERROR100.getCode());
|
wvpResult.setCode(ErrorCode.ERROR100.getCode());
|
||||||
wvpResult.setMsg("点播超时");
|
wvpResult.setMsg("点播超时");
|
||||||
requestMessage.setData(wvpResult);
|
requestMessage.setData(wvpResult);
|
||||||
resultHolder.invokeResult(requestMessage);
|
resultHolder.invokeAllResult(requestMessage);
|
||||||
inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
|
inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
|
||||||
storager.stopPlay(deviceId, channelId);
|
storager.stopPlay(deviceId, channelId);
|
||||||
});
|
});
|
||||||
@ -166,7 +166,7 @@ public class PlayController {
|
|||||||
}
|
}
|
||||||
if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
|
if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
|
||||||
try {
|
try {
|
||||||
logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
|
logger.info("[停止点播] {}/{}", device.getDeviceId(), channelId);
|
||||||
cmder.streamByeCmd(device, channelId, inviteInfo.getStream(), null, null);
|
cmder.streamByeCmd(device, channelId, inviteInfo.getStream(), null, null);
|
||||||
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
|
} catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
|
||||||
logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
|
logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
|
||||||
|
Loading…
Reference in New Issue
Block a user