@@ -1,6 +1,5 @@
package com.genersoft.iot.vmp.service.impl ;
import com.alibaba.fastjson2.JSON ;
import com.alibaba.fastjson2.JSONArray ;
import com.alibaba.fastjson2.JSONObject ;
import com.genersoft.iot.vmp.common.InviteInfo ;
@@ -17,7 +16,6 @@ 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.transmit.callback.DeferredResultHolder ;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage ;
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.media.zlm.AssistRESTfulUtils ;
@@ -28,12 +26,13 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange ;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem ;
import com.genersoft.iot.vmp.service.* ;
import com.genersoft.iot.vmp.service.bean.* ;
import com.genersoft.iot.vmp.service.bean.InviteErrorCallback ;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode ;
import com.genersoft.iot.vmp.service.bean.SSRCInfo ;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage ;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage ;
import com.genersoft.iot.vmp.utils.DateUtil ;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode ;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.beans.factory.annotation.Autowired ;
@@ -182,6 +181,12 @@ public class PlayServiceImpl implements IPlayService {
public void play ( MediaServerItem mediaServerItem , SSRCInfo ssrcInfo , Device device , String channelId ,
InviteErrorCallback < Object > callback ) {
if ( mediaServerItem = = null | | ssrcInfo = = null ) {
callback . run ( InviteErrorCode . ERROR_FOR_PARAMETER_ERROR . getCode ( ) ,
InviteErrorCode . ERROR_FOR_PARAMETER_ERROR . getMsg ( ) ,
null ) ;
return ;
}
logger . info ( " [点播开始] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验: {} " , device . getDeviceId ( ) , channelId , ssrcInfo . getPort ( ) , device . getStreamMode ( ) , ssrcInfo . getSsrc ( ) , device . isSsrcCheck ( ) ) ;
//端口获取失败的ssrcInfo 没有必要发送点播指令
@@ -375,11 +380,10 @@ public class PlayServiceImpl implements IPlayService {
Boolean result = mediaServerService . updateRtpServerSSRC ( mediaServerItem , ssrcInfo . getStream ( ) , ssrcInResponse ) ;
if ( ! result ) {
try {
logger . warn ( " [停止点播] {}/{} " , device . getDeviceId ( ) , channelId ) ;
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 ( ) ) ;
throw new ControllerException ( ErrorCode . ERROR100 . getCode ( ) , " 命令发送失败: " + e . getMessage ( ) ) ;
}
dynamicTask . stop ( timeOutTaskKey ) ;
@@ -459,11 +463,12 @@ public class PlayServiceImpl implements IPlayService {
}
private void onPublishHandlerForPlayback ( MediaServerItem mediaServerItem , JSONObject response , String deviceId , String channelId , PlayBackCallback playBackCallback ) {
private StreamInfo onPublishHandlerForPlayback ( MediaServerItem mediaServerItem , JSONObject response , String deviceId , String channelId , String startTime , String endTime ) {
StreamInfo streamInfo = onPublishHandler ( mediaServerItem , response , deviceId , channelId ) ;
PlayBackResult < StreamInfo > playBackResult = new PlayBackResult < > ( ) ;
if ( streamInfo ! = null ) {
streamInfo . setStartTime ( startTime ) ;
streamInfo . setEndTime ( endTime ) ;
DeviceChannel deviceChannel = storager . queryChannel ( deviceId , channelId ) ;
if ( deviceChannel ! = null ) {
deviceChannel . setStreamId ( streamInfo . getStream ( ) ) ;
@@ -472,20 +477,13 @@ public class PlayServiceImpl implements IPlayService {
InviteInfo inviteInfo = inviteStreamService . getInviteInfoByDeviceAndChannel ( InviteSessionType . PLAYBACK , deviceId , channelId ) ;
if ( inviteInfo ! = null ) {
inviteInfo . setStatus ( InviteSessionStatus . ok ) ;
inviteInfo . setStreamInfo ( streamInfo ) ;
inviteStreamService . updateInviteInfo ( inviteInfo ) ;
}
playBackResult . setCode ( ErrorCode . SUCCESS . getCode ( ) ) ;
playBackResult . setMsg ( ErrorCode . SUCCESS . getMsg ( ) ) ;
playBackResult . setData ( streamInfo ) ;
playBackCallback . call ( playBackResult ) ;
} else {
logger . warn ( " 录像回放调用失败! " ) ;
playBackResult . setCode ( ErrorCode . ERROR100 . getCode ( ) ) ;
playBackResult . setMsg ( " 录像回放调用失败! " ) ;
playBackCallback . call ( playBackResult ) ;
}
return streamInfo ;
}
@Override
@@ -524,23 +522,24 @@ public class PlayServiceImpl implements IPlayService {
@Override
public void playBack ( String deviceId , String channelId , String startTime ,
String endTime , InviteStream Callback inviteStreamC allback,
PlayBackCallback callback ) {
String endTime , InviteError Callback < Object > c allback) {
Device device = storager . queryVideoDevice ( deviceId ) ;
if ( device = = null ) {
return ;
}
MediaServerItem newMediaServerItem = getNewMediaServerItem ( device ) ;
SSRCInfo ssrcInfo = mediaServerService . openRTPServer ( newMediaServerItem , null , null , device . isSsrcCheck ( ) , true , 0 , false , device . getStreamModeForParam ( ) ) ;
playBack ( newMediaServerItem , ssrcInfo , deviceId , channelId , startTime , endTime , inviteStreamCallback , callback ) ;
playBack ( newMediaServerItem , ssrcInfo , deviceId , channelId , startTime , endTime , callback ) ;
}
@Override
public void playBack ( MediaServerItem mediaServerItem , SSRCInfo ssrcInfo ,
String deviceId , String channelId , String startTime ,
String endTime , InviteStream Callback infoC allB ack,
PlayBackCallback playBackCallback ) {
String endTime , InviteError Callback < Object > c allb ack) {
if ( mediaServerItem = = null | | ssrcInfo = = null ) {
callback . run ( InviteErrorCode . ERROR_FOR_PARAMETER_ERROR . getCode ( ) ,
InviteErrorCode . ERROR_FOR_PARAMETER_ERROR . getMsg ( ) ,
null ) ;
return ;
}
@@ -548,133 +547,169 @@ public class PlayServiceImpl implements IPlayService {
if ( device = = null ) {
throw new ControllerException ( ErrorCode . ERROR100 . getCode ( ) , " 设备: " + deviceId + " 不存在 " ) ;
}
logger . info ( " [回放消息 ] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验: {} " , device . getDeviceId ( ) , channelId , ssrcInfo . getPort ( ) , device . getStreamMode ( ) , ssrcInfo . getSsrc ( ) , device . isSsrcCheck ( ) ) ;
PlayBackResult < StreamInfo > playBackResult = new PlayBackResult < > ( ) ;
logger . info ( " [录像 回放] deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验: {} " ,
device . getDeviceId ( ) , channelId , startTime , endTime , ssrcInfo . getPort ( ) , device . getStreamMode ( ) ,
ssrcInfo . getSsrc ( ) , device . isSsrcCheck ( ) ) ;
// 初始化redis中的invite消息状态
InviteInfo inviteInfo = InviteInfo . getinviteInfo ( device . getDeviceId ( ) , channelId , ssrcInfo . getStream ( ) , ssrcInfo ,
mediaServerItem . getSdpIp ( ) , ssrcInfo . getPort ( ) , device . getStreamMode ( ) , InviteSessionType . PLAYBACK ,
InviteSessionStatus . ready ) ;
inviteStreamService . updateInviteInfo ( inviteInfo ) ;
String playBackTimeOutTaskKey = UUID . randomUUID ( ) . toString ( ) ;
dynamicTask . startDelay ( playBackTimeOutTaskKey , ( ) - > {
logger . warn ( String . format ( " 设备回放 超时, deviceId: %s , channelId: %s " , deviceId , channelId ) ) ;
playBackResult . setCode ( ErrorCode . ERROR100 . getCode ( ) ) ;
playBackResult . setMsg ( " 回放超时 " ) ;
logger . warn ( " [录像回放] 超时, deviceId: {} , channelId: {} " , deviceId , channelId ) ;
inviteStreamService . removeInviteInfo ( inviteInfo ) ;
callback . run ( InviteErrorCode . ERROR_FOR_SIGNALLING_TIMEOUT . getCode ( ) , InviteErrorCode . ERROR_FOR_SIGNALLING_TIMEOUT . getMsg ( ) , null ) ;
try {
cmder . streamByeCmd ( device , channelId , ssrcInfo . getStream ( ) , null ) ;
} catch ( InvalidArgumentException | ParseException | SipException e ) {
logger . error ( " [录像流] 回放超时 发送BYE失败 {} " , e . getMessage ( ) ) ;
logger . error ( " [录像回放] 超时 发送BYE失败 {} " , e . getMessage ( ) ) ;
} catch ( SsrcTransactionNotFoundException e ) {
// 点播超时回复BYE 同时释放ssrc以及此次点播的资源
mediaServerService . releaseSsrc ( mediaServerItem . getId ( ) , ssrcInfo . getSsrc ( ) ) ;
mediaServerService . closeRTPServer ( mediaServerItem , ssrcInfo . getStream ( ) ) ;
streamSession . remove ( deviceId , channelId , ssrcInfo . getStream ( ) ) ;
}
// 回复之前所有的点播请求
playBackCallback . call ( playBackResult ) ;
} , userSetting . getPlayTimeout ( ) ) ;
SipSubscribe . Event errorEvent = event - > {
logger . info ( " [录像回放] 失败,{} {} " , event . statusCode , event . msg ) ;
dynamicTask . stop ( playBackTimeOutTaskKey ) ;
playBackResult . setCode ( ErrorCode . ERROR100 . getCode ( ) ) ;
playBackResult . setMsg ( String . format ( " 回放失败, 错误码: %s, %s " , event . statusCode , event . msg ) ) ;
playBackResult . setEvent ( event ) ;
playBackCallback . call ( playBackResult ) ;
callback . run ( InviteErrorCode . ERROR_FOR_SIGNALLING_ERROR . getCode ( ) ,
String . format ( " 回放失败, 错误码: %s, %s " , event . statusCode , event . msg ) , null );
mediaServerService . releaseSsrc ( mediaServerItem . getId ( ) , ssrcInfo . getSsrc ( ) ) ;
mediaServerService . closeRTPServer ( mediaServerItem , ssrcInfo . getStream ( ) ) ;
streamSession . remove ( device . getDeviceId ( ) , channelId , ssrcInfo . getStream ( ) ) ;
inviteStreamService . removeInviteInfo ( inviteInfo ) ;
} ;
InviteStreamCallback hookEvent = ( InviteStreamInfo inviteStreamInfo ) - > {
logger . info ( " 收到回放订阅消息: " + inviteStreamInfo . getResponse ( ) . toJSONString ( ) ) ;
ZlmHttpHookSubscribe . Event hookEvent = ( mediaServerItemInuse , jsonObject ) - > {
logger . info ( " 收到回放订阅消息: " + jsonObject ) ;
dynamicTask . stop ( playBackTimeOutTaskKey ) ;
StreamInfo streamInfo = onPublishHandler( inviteStreamInfo . getM ediaServerItem( ) , inviteStreamInfo . getResponse ( ) , deviceId , channelId ) ;
StreamInfo streamInfo = onPublishHandlerForPlayback ( m ediaServerItemInuse , jsonObject , deviceId , channelId , startTime , endTime );
if ( streamInfo = = null ) {
logger . warn ( " 设备回放API调用失败! " ) ;
playBackResult . setCode ( ErrorCode . ERROR100 . getCode ( ) ) ;
playBackResult . setMsg ( " 设备回放API调用失败! " ) ;
playBackCallback . call ( playBackResult ) ;
callback . run ( InviteErrorCode . ERROR_FOR_STREAM_PARSING_EXCEPTIONS . getCode ( ) ,
InviteErrorCode . ERROR_FOR_STREAM_PARSING_EXCEPTIONS . getMsg ( ) , null ) ;
return ;
}
redisCatchStorage . startPlayback ( streamInfo , i nviteStreamInfo . getCallId ( ) ) ;
playBackResult . setCode ( ErrorCode . SUCCESS . getCode ( ) ) ;
playBackResult . setMsg ( ErrorCode . SUCCESS . getMsg ( ) ) ;
playBackResult . setData ( streamInfo ) ;
playBackResult . setMediaServerItem ( inviteStreamInfo . getMediaServerItem ( ) ) ;
playBackResult . setResponse ( inviteStreamInfo . getResponse ( ) ) ;
playBackCallback . call ( playBackResult ) ;
callback . run ( InviteErrorCode . SUCCESS . getCode ( ) , I nviteErrorCode . SUCCESS . getMsg ( ) , streamInfo ) ;
logger . info ( " [录像回放] 成功 deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {} " , device . getDeviceId ( ) , channelId , startTime , endTime ) ;
} ;
try {
cmder . playbackStreamCmd ( mediaServerItem , ssrcInfo , device , channelId , startTime , endTime , infoCallBack ,
cmder . playbackStreamCmd ( mediaServerItem , ssrcInfo , device , channelId , startTime , endTime ,
hookEvent , eventResult - > {
if ( eventResult . type = = SipSubscribe . EventResultType . response ) {
ResponseEvent responseEvent = ( ResponseEvent ) eventResult . event ;
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 ) ;
// 查询到ssrc不一致且开启了ssrc校验则需要针对处理
if ( ssrcInfo . getSsrc ( ) . equals ( ssrcInResponse ) ) {
inviteInfo . setStatus ( InviteSessionStatus . ok ) ;
ResponseEvent responseEvent = ( ResponseEvent ) eventResult . event ;
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 ) ;
// 查询到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 ) ;
if ( ! ssrcFactory . checkSsrc ( mediaServerItem . getId ( ) , ssrcInResponse ) ) {
// ssrc 不可用
logger . info ( " [录像回放] SSRC修正时发现ssrc不可使用 {}->{} " , ssrcInfo . getSsrc ( ) , ssrcInResponse ) ;
// 释放ssrc
dynamicTask . stop ( playBackTimeOutTaskKey ) ;
mediaServerService . releaseSsrc ( mediaServerItem . getId ( ) , ssrcInfo . getSsrc ( ) ) ;
streamSession . remove ( device . getDeviceId ( ) , channelId , ssrcInfo . getStream ( ) ) ;
callback . run ( InviteErrorCode . ERROR_FOR_SSRC_UNAVAILABLE . getCode ( ) ,
InviteErrorCode . ERROR_FOR_SSRC_UNAVAILABLE . getMsg ( ) , null ) ;
return ;
}
logger . info ( " [回放消息] 收到invite 200, 发现下级自定义了ssrc: {} " , ssrcInResponse ) ;
if ( ! mediaServerItem . isRtpEnable ( ) | | device . isSsrcCheck ( ) ) {
logger . info ( " [回放消息] SSRC修正 {}->{} " , ssrcInfo . getSsrc ( ) , ssrcInResponse ) ;
if ( ! ssrcFactory . checkSsrc ( mediaServerItem . getId ( ) , ssrcInResponse ) ) {
// ssrc 不可用
// 释放ssrc
// 单端口模式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 ) ;
inviteInfo . setStream ( stream ) ;
subscribe . addSubscribe ( hookSubscribe , ( MediaServerItem mediaServerItemInUse , JSONObject response ) - > {
logger . info ( " [ZLM HOOK] ssrc修正后收到订阅消息: " + response . toJSONString ( ) ) ;
dynamicTask . stop ( playBackTimeOutTaskKey ) ;
mediaServerService . releaseSsrc ( mediaServerItem . getId ( ) , ssrcInfo . getSsrc ( ) ) ;
streamSession . remov e ( device . getDeviceId ( ) , channelId , ssrcInfo . getStream ( ) ) ;
eventResult . msg = " 下级自定义了ssrc,但是此ssrc不可用 " ;
eventResult . statusCode = 400 ;
errorEvent . response ( eventResult ) ;
return ;
}
// 单端口模式streamId也有变化, 需要重新设置监听
if ( ! mediaServerItem . isRtpEnable ( ) ) {
// 添加订阅
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory . on_stream_changed ( " rtp " , ssrcInfo . getStream ( ) , true , " rtsp " , mediaServerItem . getId ( ) ) ;
subscribe . removeSubscribe ( hookSubscribe ) ;
hookSubscribe . getContent ( ) . put ( " stream " , String . format ( " %08x " , Integer . parseInt ( ssrcInResponse ) ) . toUpperCase ( ) ) ;
subscribe . addSubscribe ( hookSubscribe , ( MediaServerItem mediaServerItemInUse , JSONObject response ) - > {
logger . info ( " [ZLM HOOK] ssrc修正后收到订阅消息: " + response . toJSONString ( ) ) ;
dynamicTask . stop ( playBackTimeOutTaskKey ) ;
// hook响应
onPublishHandlerForPlayback ( mediaServerItemInUse , response , device . getDeviceId ( ) , channelId , playBackCallback ) ;
hookEvent . call ( new InviteStreamInfo ( mediaServerItem , null , eventResult . callId , " rtp " , ssrcInfo . getStream ( ) ) ) ;
} ) ;
}
// 关闭rtp server
mediaServerService . closeRTPServer ( mediaServerItem , ssrcInfo . getStream ( ) , result - > {
if ( result ) {
// 重新开启ssrc server
mediaServerService . openRTPServer ( mediaServerItem , ssrcInfo . getStream ( ) , ssrcInResponse , device . isSsrcCheck ( ) , true , ssrcInfo . getPort ( ) , true , device . getStreamModeForParam ( ) ) ;
} else {
try {
logger . warn ( " [回放消息]停止 {}/{} " , device . getDeviceId ( ) , channelId ) ;
cmder . streamByeCmd ( device , channelId , ssrcInfo . getStream ( ) , null , null ) ;
} catch ( InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e ) {
logger . error ( " [命令发送失败] 停止点播 停止, 发送BYE: {} " , e . getMessage ( ) ) ;
throw new ControllerException ( ErrorCode . ERROR100 . getCode ( ) , " 命令发送失败: " + e . getMessage ( ) ) ;
}
dynamicTask . stop ( playBackTimeOutTaskKey ) ;
// 释放ssrc
mediaServerService . releaseSsrc ( mediaServerItem . getId ( ) , ssrcInfo . getSsrc ( ) ) ;
streamSession . remove ( device . getDeviceId ( ) , channelId , ssrcInfo . getStream ( ) ) ;
errorEvent . response ( eventResult ) ;
eventResult . msg = " 下级自定义了ssrc,重新设置收流信息失败 " ;
eventResult . statusCode = 500 ;
errorEvent . response ( eventResult ) ;
}
// hook响应
hookEvent . respons e ( mediaServerItemInUse , response ) ;
} ) ;
}
// 更新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 {
ssrcInfo . setSsrc ( ssrcInResponse ) ;
inviteInfo . setSsrcInfo ( ssrcInfo ) ;
inviteInfo . setStream ( ssrcInfo . getStream ( ) ) ;
}
} else {
logger . info ( " [点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正 " ) ;
}
}
inviteStreamService . updateInviteInfo ( inviteInfo ) ;
} , errorEvent ) ;
} catch ( InvalidArgumentException | SipException | ParseException e ) {
logger . error ( " [命令发送失败] 回放: {} " , e . getMessage ( ) ) ;
@@ -690,42 +725,50 @@ public class PlayServiceImpl implements IPlayService {
@Override
public void download ( String deviceId , String channelId , String startTime , String endTime , int downloadSpeed , InviteStream Callback infoCallBack , PlayBackCallback playBackC allback) {
public void download ( String deviceId , String channelId , String startTime , String endTime , int downloadSpeed , InviteError Callback < Object > c allback) {
Device device = storager . queryVideoDevice ( deviceId ) ;
if ( device = = null ) {
return ;
}
MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist ( device ) ;
if ( newMediaServerItem = = null ) {
PlayBackResult < StreamInfo > downloadResult = new PlayBackResult < > ( ) ;
downloadResult . setCode ( ErrorCode . ERROR100 . getCode ( ) ) ;
downloadResult . setMsg ( " 未找到assist服务 " ) ;
playBackCallback . call ( downloadResult ) ;
callback . run ( InviteErrorCode . ERROR_FOR_ASSIST_NOT_READY . getCode ( ) ,
InviteErrorCode . ERROR_FOR_ASSIST_NOT_READY . getMsg ( ) ,
null ) ;
return ;
}
SSRCInfo ssrcInfo = mediaServerService . openRTPServer ( newMediaServerItem , null , null , device . isSsrcCheck ( ) , true , 0 , false , device . getStreamModeForParam ( ) ) ;
download ( newMediaServerItem , ssrcInfo , deviceId , channelId , startTime , endTime , downloadSpeed , infoCallBack , playBackC allback) ;
download ( newMediaServerItem , ssrcInfo , deviceId , channelId , startTime , endTime , downloadSpeed , c allback) ;
}
@Override
public void download ( MediaServerItem mediaServerItem , SSRCInfo ssrcInfo , String deviceId , String channelId , String startTime , String endTime , int downloadSpeed , InviteStream Callback infoCallBack , PlayBackCallback hookCallB ack) {
public void download ( MediaServerItem mediaServerItem , SSRCInfo ssrcInfo , String deviceId , String channelId , String startTime , String endTime , int downloadSpeed , InviteError Callback < Object > callb ack) {
if ( mediaServerItem = = null | | ssrcInfo = = null ) {
callback . run ( InviteErrorCode . ERROR_FOR_PARAMETER_ERROR . getCode ( ) ,
InviteErrorCode . ERROR_FOR_PARAMETER_ERROR . getMsg ( ) ,
null ) ;
return ;
}
Device device = storager . queryVideoDevice ( deviceId ) ;
if ( device = = null ) {
throw new ControllerException ( ErrorCode . ERROR400 . getCode ( ) , " 设备: " + deviceId + " 不存在 " ) ;
callback . run ( InviteErrorCode . ERROR_FOR_PARAMETER_ERROR . getCode ( ) ,
" 设备: " + deviceId + " 不存在 " ,
null ) ;
return ;
}
PlayBackResult < StreamInfo > downloadResult = new PlayBackResult < > ( ) ;
logger . info ( " [录像下载] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验: {} " , device . getDeviceId ( ) , channelId , ssrcInfo . getPort ( ) , device . getStreamMode ( ) , ssrcInfo . getSsrc ( ) , device . isSsrcCheck ( ) ) ;
// 初始化redis中的invite消息状态
InviteInfo inviteInfo = InviteInfo . getinviteInfo ( device . getDeviceId ( ) , channelId , ssrcInfo . getStream ( ) , ssrcInfo ,
mediaServerItem . getSdpIp ( ) , ssrcInfo . getPort ( ) , device . getStreamMode ( ) , InviteSessionType . DOWNLOAD ,
InviteSessionStatus . ready ) ;
inviteStreamService . updateInviteInfo ( inviteInfo ) ;
String downLoadTimeOutTaskKey = UUID . randomUUID ( ) . toString ( ) ;
dynamicTask . startDelay ( downLoadTimeOutTaskKey , ( ) - > {
logger . warn ( String . format ( " 录像下载请求超时, deviceId: %s , channelId: %s " , deviceId , channelId ) ) ;
downloadResult . setCode ( ErrorCode . ERROR100 . getCode ( ) ) ;
downloadResult . setMsg ( " 录像下载请求超时 " ) ;
hookCallBack . call ( downloadRes ult ) ;
inviteStreamService . removeInviteInfo ( inviteInfo ) ;
callback . run ( InviteErrorCode . ERROR_FOR_SIGNALLING_TIMEOUT . getCode ( ) ,
InviteErrorCode . ERROR_FOR_SIGNALLING_TIMEOUT . getMsg ( ) , n ull ) ;
// 点播超时回复BYE 同时释放ssrc以及此次点播的资源
try {
@@ -741,98 +784,129 @@ public class PlayServiceImpl implements IPlayService {
SipSubscribe . Event errorEvent = event - > {
dynamicTask . stop ( downLoadTimeOutTaskKey ) ;
downloadResult . setCode ( ErrorCode . ERROR100 . getCode ( ) ) ;
downloadResult . setMsg ( String . format ( " 录像下载失败, 错误码: %s, %s " , event . statusCode , event . msg ) ) ;
downloadResult . setEvent ( event ) ;
hookCallBack . call ( downloadResult ) ;
callback . run ( InviteErrorCode . ERROR_FOR_SIGNALLING_TIMEOUT . getCode ( ) ,
String . format ( " 录像下载失败, 错误码: %s, %s " , event . statusCode , event . msg ) , null );
streamSession . remove ( device . getDeviceId ( ) , channelId , ssrcInfo . getStream ( ) ) ;
inviteStreamService . removeInviteInfo ( inviteInfo ) ;
} ;
InviteStreamCallback hookEvent = ( InviteStreamInfo inviteStreamInfo ) - > {
logger . info ( " [录像下载]收到订阅消息: " + inviteStreamInfo . getCallId ( ) ) ;
ZlmHttpHookSubscribe . Event hookEvent = ( mediaServerItemInuse , jsonObject ) - > {
logger . info ( " [录像下载]收到订阅消息: " + jsonObject ) ;
dynamicTask . stop ( downLoadTimeOutTaskKey ) ;
StreamInfo streamInfo = onPublishHandler( inviteStreamInfo . getM ediaServerItem( ) , inviteStreamInfo . getResponse ( ) , deviceId , channelId ) ;
streamInfo . setStartTime ( startTime ) ;
streamInfo . setEndTime ( endTime ) ;
redisCatchStorage . startDownload ( streamInfo , inviteStreamInfo . getCallId ( ) ) ;
downloadResult . setCode ( ErrorCode . SUCCES S . getCode ( ) ) ;
downloadResult . setMsg ( ErrorCode . SUCCESS . getMsg ( ) ) ;
downloadResult . setData ( streamInfo ) ;
downloadResult . setMediaServerItem ( inviteStreamInfo . getMediaServerItem ( ) ) ;
downloadResult . setResponse ( inviteStreamInfo . getResponse ( ) ) ;
hookCallBack . call ( downloadResult ) ;
StreamInfo streamInfo = onPublishHandlerForDownload ( m ediaServerItemInuse , jsonObject , deviceId , channelId , startTime , endTime );
if ( streamInfo = = null ) {
logger . warn ( " [录像下载] 获取流地址信息失败 " ) ;
callback . run ( InviteErrorCode . ERROR_FOR_STREAM_PARSING_EXCEPTIONS . getCode ( ) ,
InviteErrorCode . ERROR_FOR_STREAM_PARSING_EXCEPTION S . getMsg ( ) , null );
return ;
}
callback . run ( InviteErrorCode . SUCCESS . getCode ( ) , InviteErrorCode . SUCCESS . getMsg ( ) , streamInfo ) ;
logger . info ( " [录像下载] 调用成功 deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {} " , device . getDeviceId ( ) , channelId , startTime , endTime ) ;
} ;
try {
cmder . downloadStreamCmd ( mediaServerItem , ssrcInfo , device , channelId , startTime , endTime , downloadSpeed , infoCallBack ,
hookEvent , errorEvent , eventResult - >
{
if ( eventResult . type = = SipSubscribe . E ventResultType . response ) {
ResponseEvent responseEvent = ( R esponseEvent) eventResult . event ;
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 ) ;
// 查询到ssrc不一致且开启了ssrc校验则需要针对处理
if ( ssrcInfo . getSsrc ( ) . equals( ssrcInResponse ) ) {
return ;
}
logger . info ( " [录像下载] 收到invite 200, 发现下级自定义了ssrc: {} " , ssrcInResponse ) ;
if ( ! mediaServerItem . isRtpEnable ( ) | | device . isSsrcCheck ( ) ) {
logger . info ( " [录像下载] SSRC修正 {}->{} " , ssrcInfo . getSsrc ( ) , ssrcInRespons e ) ;
cmder . downloadStreamCmd ( mediaServerItem , ssrcInfo , device , channelId , startTime , endTime , downloadSpeed ,
hookEvent , errorEvent , eventResult - > {
inviteInfo . setStatus ( InviteSessionStatus . ok ) ;
ResponseEvent responseEvent = ( ResponseEvent ) e ventResult. event ;
String contentString = new String ( r esponseEvent. 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 ) ;
// 查询到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 ( tru e ) ;
for ( Object description : mediaDescriptions ) {
MediaDescription mediaDescription = ( MediaDescription ) description ;
Media media = mediaDescription . getMedia ( ) ;
if ( ! ssrcFactory . checkSsrc ( mediaServerItem . getId ( ) , ssrcInResponse ) ) {
// ssrc 不可用
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 ( ) ) ;
eventResult . msg = " 下级自定义了ssrc,但是此ssrc不可用 " ;
eventResult . statusCode = 400 ;
errorEvent . response ( eventRes ult ) ;
return ;
callback . run ( InviteErrorCode . ERROR_FOR_SDP_PARSING_EXCEPTIONS . getCode ( ) ,
InviteErrorCode . ERROR_FOR_SDP_PARSING_EXCEPTIONS . getMsg ( ) , n ull ) ;
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 ) ;
// 单端口模式streamId也有变化, 需要重新设置监听
if ( ! mediaServerItem . isRtpEnable ( ) ) {
// 添加订阅
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory . on_stream_changed ( " rtp " , ssrcInfo . getStream ( ) , true , " rtsp " , mediaServerItem . getId ( ) ) ;
subscribe . removeSubscribe ( hookSubscribe ) ;
hookSubscribe . getContent ( ) . put ( " stream " , String . format ( " %08x " , Integer . parseInt ( ssrcInResponse ) ) . toUpperCas e ( ) ) ;
subscribe . addSubscribe ( hookSubscribe , ( MediaServerItem mediaServerItemInUse , JSONObject response ) - > {
logger . info ( " [ZLM HOOK] ssrc修正后收到订阅消息: " + response . toJSONString ( ) ) ;
dynamicTask . stop ( downLoadTimeOutTaskKey ) ;
// hook响应
onPublishHandlerForPlayback ( mediaServerItemInUse , response , device . getDeviceId ( ) , channelId , hookCallBack ) ;
hookEvent . call ( new InviteStreamInfo ( mediaServerItem , null , eventResult . callId , " rtp " , ssrcInfo . getStream ( ) ) ) ;
} ) ;
}
if ( ! ssrcFactory . checkSsrc ( mediaServerItem . getId ( ) , ssrcInResponse ) ) {
// ssrc 不可用
// 释放ssrc
mediaServerService . releaseSsrc ( mediaServerItem . getId ( ) , ssrcInfo . getSsrc ( ) ) ;
streamSession . remove ( device . getDeviceId ( ) , channelId , ssrcInfo . getStream ( ) ) ;
callback . run ( InviteErrorCode . ERROR_FOR_SSRC_UNAVAILABLE . getCod e ( ) ,
InviteErrorCode . ERROR_FOR_SSRC_UNAVAILABLE . getMsg ( ) , null ) ;
return ;
}
// 关闭rtp server
mediaServerService . closeRTPServer ( mediaServerItem , ssrcInfo . getStream ( ) , result - > {
if ( result ) {
// 重新开启ssrc server
mediaServerService . openRTPServer ( mediaServerItem , ssrcInfo . getStream ( ) , ssrcInResponse , device . isSsrcCheck ( ) , true , ssrcInfo . getPort ( ) , true , device . getStreamModeForParam ( ) ) ;
} else {
try {
logger . warn ( " [录像下载] 停止{}/{} " , device . getDeviceId ( ) , channelId ) ;
cmder . streamByeCmd ( device , channelId , ssrcInfo . getStream ( ) , null , null ) ;
} catch ( InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e ) {
logger . error ( " [命令发送失败] 录像下载停止, 发送BYE: {} " , e . getMessage ( ) ) ;
throw new ControllerException ( ErrorCode . ERROR100 . getCode ( ) , " 命令发送失败: " + e . getMessage ( ) ) ;
}
dynamicTask . stop ( downLoadTimeOutTaskKey ) ;
// 释放ssrc
mediaServerService . releaseSsrc ( mediaServerItem . getId ( ) , ssrcInfo . getSsrc ( ) ) ;
streamSession . remove ( device . getDeviceId ( ) , channelId , ssrcInfo . getStream ( ) ) ;
eventResult . msg = " 下级自定义了ssrc,重新设置收流信息失败 " ;
eventResult . statusCode = 500 ;
errorEvent . response ( eventResult ) ;
}
// 单端口模式streamId也有变化, 需要重新设置监听
if ( ! mediaServerItem . isRtpEnable ( ) ) {
// 添加订阅
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory . on_stream_changed ( " rtp " , ssrcInfo . getStream ( ) , true , " rtsp " , mediaServerItem . getId ( ) ) ;
subscribe . removeSubscribe ( hookSubscribe ) ;
hookSubscribe . getContent ( ) . put ( " stream " , String . format ( " %08x " , Integer . parseInt ( ssrcInResponse ) ) . toUpperCase ( ) ) ;
subscribe . addSubscribe ( hookSubscribe , ( MediaServerItem mediaServerItemInUse , JSONObject response ) - > {
logger . info ( " [ZLM HOOK] ssrc修正后收到订阅消息: " + response . toJSONString ( ) ) ;
dynamicTask . stop ( downLoadTimeOutTaskKey ) ;
hookEvent . response ( mediaServerItemInUse , response ) ;
} ) ;
}
// 更新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 {
ssrcInfo . setSsrc ( ssrcInResponse ) ;
inviteInfo . setSsrcInfo ( ssrcInfo ) ;
inviteInfo . setStream ( ssrcInfo . getStream ( ) ) ;
}
} else {
logger . info ( " [录像下载] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正 " ) ;
}
}
} ) ;
@@ -849,21 +923,22 @@ public class PlayServiceImpl implements IPlayService {
@Override
public StreamInfo getDownLoadInfo ( String deviceId , String channelId , String stream ) {
Stream Info stream Info = redisCatchStorage . queryDownload ( deviceId , channelId , stream , null );
if ( streamInfo ! = null ) {
if ( stream Info. getProgress ( ) = = 1 ) {
return streamInfo ;
Invite Info invite Info = inviteStreamService . getInviteInfo ( InviteSessionType . DOWNLOAD , deviceId , channelId , stream ) ;
if ( inviteInfo ! = null & & invite Info. getStreamInfo ( ) ! = null ) {
if ( inviteInfo . getStreamInfo ( ) . getProgress ( ) = = 1 ) {
return inviteInfo . getStreamInfo ( ) ;
}
// 获取当前已下载时长
String mediaServerId = s treamInfo. getMediaServerId ( ) ;
String mediaServerId = inviteInfo . getS treamInfo( ) .getMediaServerId ( ) ;
MediaServerItem mediaServerItem = mediaServerService . getOne ( mediaServerId ) ;
if ( mediaServerItem = = null ) {
logger . warn ( " 查询录像信息时发现节点已离线 " ) ;
return null ;
}
if ( mediaServerItem . getRecordAssistPort ( ) > 0 ) {
JSONObject jsonObject = assistRESTfulUtils . fileDuration ( mediaServerItem , s treamInfo. getApp ( ) , s treamInfo. getStream ( ) , null ) ;
JSONObject jsonObject = assistRESTfulUtils . fileDuration ( mediaServerItem , inviteInfo . getS treamInfo( ) .getApp ( ) , inviteInfo . getS treamInfo( ) .getStream ( ) , null ) ;
if ( jsonObject = = null ) {
throw new ControllerException ( ErrorCode . ERROR100 . getCode ( ) , " 连接Assist服务失败 " ) ;
}
@@ -871,10 +946,10 @@ public class PlayServiceImpl implements IPlayService {
long duration = jsonObject . getLong ( " data " ) ;
if ( duration = = 0 ) {
s treamInfo. setProgress ( 0 ) ;
inviteInfo . getS treamInfo( ) .setProgress ( 0 ) ;
} else {
String startTime = s treamInfo. getStartTime ( ) ;
String endTime = s treamInfo. getEndTime ( ) ;
String startTime = inviteInfo . getS treamInfo( ) .getStartTime ( ) ;
String endTime = inviteInfo . getS treamInfo( ) .getEndTime ( ) ;
long start = DateUtil . yyyy_MM_dd_HH_mm_ssToTimestamp ( startTime ) ;
long end = DateUtil . yyyy_MM_dd_HH_mm_ssToTimestamp ( endTime ) ;
@@ -882,30 +957,31 @@ public class PlayServiceImpl implements IPlayService {
BigDecimal totalCount = new BigDecimal ( end - start ) ;
BigDecimal divide = currentCount . divide ( totalCount , 2 , RoundingMode . HALF_UP ) ;
double process = divide . doubleValue ( ) ;
s treamInfo. setProgress ( process ) ;
inviteInfo . getS treamInfo( ) .setProgress ( process ) ;
}
inviteStreamService . updateInviteInfo ( inviteInfo ) ;
}
}
return inviteInfo . getStreamInfo ( ) ;
}
return null ;
}
private StreamInfo onPublishHandlerForDownload ( MediaServerItem mediaServerItemInuse , JSONObject response , String deviceId , String channelId , String startTime , String endTime ) {
StreamInfo streamInfo = onPublishHandler ( mediaServerItemInuse , response , deviceId , channelId ) ;
if ( streamInfo ! = null ) {
streamInfo . setStartTime ( startTime ) ;
streamInfo . setEndTime ( endTime ) ;
InviteInfo inviteInfo = inviteStreamService . getInviteInfoByDeviceAndChannel ( InviteSessionType . DOWNLOAD , deviceId , channelId ) ;
if ( inviteInfo ! = null ) {
inviteInfo . setStatus ( InviteSessionStatus . ok ) ;
inviteInfo . setStreamInfo ( streamInfo ) ;
inviteStreamService . updateInviteInfo ( inviteInfo ) ;
}
}
return streamInfo ;
}
private void onPublishHandlerForDownload ( InviteStreamInfo inviteStreamInfo , String deviceId , String channelId , String uuid ) {
RequestMessage msg = new RequestMessage ( ) ;
msg . setKey ( DeferredResultHolder . CALLBACK_CMD_DOWNLOAD + deviceId + channelId ) ;
msg . setId ( uuid ) ;
StreamInfo streamInfo = onPublishHandler ( inviteStreamInfo . getMediaServerItem ( ) , inviteStreamInfo . getResponse ( ) , deviceId , channelId ) ;
if ( streamInfo ! = null ) {
redisCatchStorage . startDownload ( streamInfo , inviteStreamInfo . getCallId ( ) ) ;
msg . setData ( JSON . toJSONString ( streamInfo ) ) ;
resultHolder . invokeResult ( msg ) ;
} else {
logger . warn ( " 设备预览API调用失败! " ) ;
msg . setData ( WVPResult . fail ( ErrorCode . ERROR100 . getCode ( ) , " 设备预览API调用失败! " ) ) ;
resultHolder . invokeResult ( msg ) ;
}
}
public StreamInfo onPublishHandler ( MediaServerItem mediaServerItem , JSONObject resonse , String deviceId , String channelId ) {
String streamId = resonse . getString ( " stream " ) ;
@@ -1007,15 +1083,14 @@ public class PlayServiceImpl implements IPlayService {
@Override
public void pauseRtp ( String streamId ) throws ServiceException , InvalidArgumentException , ParseException , SipException {
String key = redisCatchStorage . queryPlaybackForKey ( null , null , streamId , null );
StreamInfo stream Info = redisCatchStorage . queryPlayback ( null , null , streamId , null ) ;
if ( null = = streamInfo ) {
InviteInfo inviteInfo = inviteStreamService . getInviteInfoByStream ( InviteSessionType . PLAYBACK , streamId ) ;
if ( null = = invite Info | | inviteInfo . getStreamInfo ( ) = = null ) {
logger . warn ( " streamId不存在! " ) ;
throw new ServiceException ( " streamId不存在 " ) ;
}
s treamInfo. setPause ( true ) ;
redisTemplate . opsForValue ( ) . set ( key , stream Info) ;
MediaServerItem mediaServerItem = mediaServerService . getOne ( s treamInfo. getMediaServerId ( ) ) ;
inviteInfo . getS treamInfo( ) .setPause ( true ) ;
inviteStreamService . updateInviteInfo ( invite Info) ;
MediaServerItem mediaServerItem = mediaServerService . getOne ( inviteInfo . getS treamInfo( ) .getMediaServerId ( ) ) ;
if ( null = = mediaServerItem ) {
logger . warn ( " mediaServer 不存在! " ) ;
throw new ServiceException ( " mediaServer不存在 " ) ;
@@ -1025,21 +1100,20 @@ public class PlayServiceImpl implements IPlayService {
if ( jsonObject = = null | | jsonObject . getInteger ( " code " ) ! = 0 ) {
throw new ServiceException ( " 暂停RTP接收失败 " ) ;
}
Device device = storager . queryVideoDevice ( stream Info. getDeviceID ( ) ) ;
cmder . playPauseCmd ( device , s treamInfo) ;
Device device = storager . queryVideoDevice ( invite Info. getDeviceId ( ) ) ;
cmder . playPauseCmd ( device , inviteInfo . getS treamInfo( ) );
}
@Override
public void resumeRtp ( String streamId ) throws ServiceException , InvalidArgumentException , ParseException , SipException {
String key = redisCatchStorage . queryPlaybackForKey ( null , null , streamId , null );
StreamInfo stream Info = redisCatchStorage . queryPlayback ( null , null , streamId , null ) ;
if ( null = = streamInfo ) {
InviteInfo inviteInfo = inviteStreamService . getInviteInfoByStream ( InviteSessionType . PLAYBACK , streamId ) ;
if ( null = = invite Info | | inviteInfo . getStreamInfo ( ) = = null ) {
logger . warn ( " streamId不存在! " ) ;
throw new ServiceException ( " streamId不存在 " ) ;
}
s treamInfo. setPause ( false ) ;
redisTemplate . opsForValue ( ) . set ( key , stream Info) ;
MediaServerItem mediaServerItem = mediaServerService . getOne ( s treamInfo. getMediaServerId ( ) ) ;
inviteInfo . getS treamInfo( ) .setPause ( false ) ;
inviteStreamService . updateInviteInfo ( invite Info) ;
MediaServerItem mediaServerItem = mediaServerService . getOne ( inviteInfo . getS treamInfo( ) .getMediaServerId ( ) ) ;
if ( null = = mediaServerItem ) {
logger . warn ( " mediaServer 不存在! " ) ;
throw new ServiceException ( " mediaServer不存在 " ) ;
@@ -1049,7 +1123,7 @@ public class PlayServiceImpl implements IPlayService {
if ( jsonObject = = null | | jsonObject . getInteger ( " code " ) ! = 0 ) {
throw new ServiceException ( " 继续RTP接收失败 " ) ;
}
Device device = storager . queryVideoDevice ( stream Info. getDeviceID ( ) ) ;
cmder . playResumeCmd ( device , s treamInfo) ;
Device device = storager . queryVideoDevice ( invite Info. getDeviceId ( ) ) ;
cmder . playResumeCmd ( device , inviteInfo . getS treamInfo( ) );
}
}