| | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.conf.DynamicTask; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| | | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; |
| | | import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch; |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| | | import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
| | | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.service.IMediaServerService; |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; |
| | | import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; |
| | | import com.genersoft.iot.vmp.media.bean.MediaServer; |
| | | import com.genersoft.iot.vmp.service.IDeviceService; |
| | | import com.genersoft.iot.vmp.media.service.IMediaServerService; |
| | | import com.genersoft.iot.vmp.service.IPlayService; |
| | | import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; |
| | | import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; |
| | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.sip.InvalidArgumentException; |
| | | import javax.sip.RequestEvent; |
| | | import javax.sip.SipException; |
| | | import javax.sip.address.SipURI; |
| | | import javax.sip.header.CallIdHeader; |
| | | import javax.sip.header.FromHeader; |
| | | import javax.sip.header.HeaderAddress; |
| | | import javax.sip.header.ToHeader; |
| | | import java.text.ParseException; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Autowired |
| | | private UserSetting userSetting; |
| | | |
| | | @Autowired |
| | | private IVideoManagerStorage storager; |
| | | |
| | | @Autowired |
| | | private ZLMRTPServerFactory zlmrtpServerFactory; |
| | | private IDeviceService deviceService; |
| | | |
| | | @Autowired |
| | | private ZlmHttpHookSubscribe hookSubscribe; |
| | | private ZLMServerFactory zlmServerFactory; |
| | | |
| | | @Autowired |
| | | private HookSubscribe hookSubscribe; |
| | | |
| | | @Autowired |
| | | private IMediaServerService mediaServerService; |
| | |
| | | private RedisGbPlayMsgListener redisGbPlayMsgListener; |
| | | |
| | | @Autowired |
| | | private UserSetting userSetting; |
| | | |
| | | @Autowired |
| | | private IPlayService playService; |
| | | |
| | | |
| | |
| | | @Override |
| | | public void process(RequestEvent evt) { |
| | | CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); |
| | | dynamicTask.stop(callIdHeader.getCallId()); |
| | | String fromUserId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); |
| | | String toUserId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); |
| | | logger.info("[收到ACK]: 来自->{}", fromUserId); |
| | | SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); |
| | | if (sendRtpItem == null) { |
| | | logger.warn("[收到ACK]:未找到来自{},目标为({})的推流信息",fromUserId, toUserId); |
| | | return; |
| | | } |
| | | // tcp主动时,此时是级联下级平台,在回复200ok时,本地已经请求zlm开启监听,跳过下面步骤 |
| | | if (sendRtpItem.isTcpActive()) { |
| | | logger.info("收到ACK,rtp/{} TCP主动方式后续处理", sendRtpItem.getStream()); |
| | | return; |
| | | } |
| | | MediaServer mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, 协议:{}", |
| | | sendRtpItem.getStream(), |
| | | sendRtpItem.getIp(), |
| | | sendRtpItem.getPort(), |
| | | sendRtpItem.getSsrc(), |
| | | sendRtpItem.isTcp()?(sendRtpItem.isTcpActive()?"TCP主动":"TCP被动"):"UDP" |
| | | ); |
| | | ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(fromUserId); |
| | | |
| | | String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); |
| | | logger.info("[收到ACK]: platformGbId->{}", platformGbId); |
| | | if (userSetting.getPushStreamAfterAck()) { |
| | | ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformGbId); |
| | | // 取消设置的超时任务 |
| | | dynamicTask.stop(callIdHeader.getCallId()); |
| | | String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); |
| | | SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); |
| | | if (sendRtpItem == null) { |
| | | logger.warn("[收到ACK]:未找到通道({})的推流信息", channelId); |
| | | return; |
| | | } |
| | | String isUdp = sendRtpItem.isTcp() ? "0" : "1"; |
| | | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| | | logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStreamId(), |
| | | sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp()); |
| | | Map<String, Object> param = new HashMap<>(12); |
| | | param.put("vhost","__defaultVhost__"); |
| | | param.put("app",sendRtpItem.getApp()); |
| | | param.put("stream",sendRtpItem.getStreamId()); |
| | | param.put("ssrc", sendRtpItem.getSsrc()); |
| | | param.put("src_port", sendRtpItem.getLocalPort()); |
| | | param.put("pt", sendRtpItem.getPt()); |
| | | param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0"); |
| | | param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0"); |
| | | param.put("is_udp", isUdp); |
| | | if (!sendRtpItem.isTcp()) { |
| | | // udp模式下开启rtcp保活 |
| | | param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0"); |
| | | } |
| | | |
| | | if (mediaInfo == null) { |
| | | if (parentPlatform != null) { |
| | | if (!userSetting.getServerId().equals(sendRtpItem.getServerId())) { |
| | | RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance( |
| | | sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(), |
| | | sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStream(), |
| | | sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(), |
| | | sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio()); |
| | | redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> { |
| | | playService.startSendRtpStreamHand(sendRtpItem, parentPlatform, json, param, callIdHeader); |
| | | playService.startSendRtpStreamFailHand(sendRtpItem, parentPlatform, callIdHeader); |
| | | }); |
| | | } else { |
| | | // 如果是非严格模式,需要关闭端口占用 |
| | | JSONObject startSendRtpStreamResult = null; |
| | | if (sendRtpItem.getLocalPort() != 0) { |
| | | HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(sendRtpItem.getSsrc(), null, mediaInfo.getId()); |
| | | hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout); |
| | | if (zlmrtpServerFactory.releasePort(mediaInfo, sendRtpItem.getSsrc())) { |
| | | if (sendRtpItem.isTcpActive()) { |
| | | startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param); |
| | | }else { |
| | | param.put("dst_url", sendRtpItem.getIp()); |
| | | param.put("dst_port", sendRtpItem.getPort()); |
| | | startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| | | } |
| | | } |
| | | }else { |
| | | try { |
| | | if (sendRtpItem.isTcpActive()) { |
| | | startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param); |
| | | }else { |
| | | param.put("dst_url", sendRtpItem.getIp()); |
| | | param.put("dst_port", sendRtpItem.getPort()); |
| | | startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| | | mediaServerService.startSendRtpPassive(mediaInfo, parentPlatform, sendRtpItem, null); |
| | | } else { |
| | | mediaServerService.startSendRtpStream(mediaInfo, parentPlatform, sendRtpItem); |
| | | } |
| | | } |
| | | if (startSendRtpStreamResult != null) { |
| | | playService.startSendRtpStreamHand(sendRtpItem, parentPlatform, startSendRtpStreamResult, param, callIdHeader); |
| | | }catch (ControllerException e) { |
| | | logger.error("RTP推流失败: {}", e.getMessage()); |
| | | playService.startSendRtpStreamFailHand(sendRtpItem, parentPlatform, callIdHeader); |
| | | } |
| | | } |
| | | }else { |
| | | Device device = deviceService.getDevice(fromUserId); |
| | | if (device == null) { |
| | | logger.warn("[收到ACK]:来自{},目标为({})的推流信息为找到流体服务[{}]信息",fromUserId, toUserId, sendRtpItem.getMediaServerId()); |
| | | return; |
| | | } |
| | | // 设置为收到ACK后发送语音的设备已经在发送200OK开始发流了 |
| | | if (!device.isBroadcastPushAfterAck()) { |
| | | return; |
| | | } |
| | | if (mediaInfo == null) { |
| | | logger.warn("[收到ACK]:来自{},目标为({})的推流信息为找到流体服务[{}]信息",fromUserId, toUserId, sendRtpItem.getMediaServerId()); |
| | | return; |
| | | } |
| | | try { |
| | | if (sendRtpItem.isTcpActive()) { |
| | | mediaServerService.startSendRtpPassive(mediaInfo, null, sendRtpItem, null); |
| | | } else { |
| | | mediaServerService.startSendRtpStream(mediaInfo, null, sendRtpItem); |
| | | } |
| | | }catch (ControllerException e) { |
| | | logger.error("RTP推流失败: {}", e.getMessage()); |
| | | playService.startSendRtpStreamFailHand(sendRtpItem, null, callIdHeader); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | } |