| | |
| | | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| | | import com.genersoft.iot.vmp.conf.DynamicTask; |
| | | import com.genersoft.iot.vmp.conf.SipConfig; |
| | | import com.genersoft.iot.vmp.conf.UserSetting; |
| | |
| | | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; |
| | | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| | |
| | | private IMediaServerService mediaServerService; |
| | | |
| | | @Autowired |
| | | private IMediaService mediaService; |
| | | private ISIPCommander commander; |
| | | |
| | | @Autowired |
| | | private ZLMRESTfulUtils zlmresTfulUtils; |
| | |
| | | |
| | | MediaServerItem mediaServerItem = null; |
| | | StreamPushItem streamPushItem = null; |
| | | StreamProxyItem proxyByAppAndStream =null; |
| | | StreamProxyItem proxyByAppAndStream = null; |
| | | // 不是通道可能是直播流 |
| | | if (channel != null && gbStream == null) { |
| | | // 通道存在,发100,TRYING |
| | |
| | | } |
| | | return; |
| | | } else { |
| | | logger.info("通道不存在,返回404"); |
| | | logger.info("通道不存在,返回404: {}", channelId); |
| | | try { |
| | | // 通道不存在,发404,资源不存在 |
| | | responseAck(request, Response.NOT_FOUND); |
| | |
| | | return; |
| | | } |
| | | String username = sdp.getOrigin().getUsername(); |
| | | String addressStr = sdp.getOrigin().getAddress(); |
| | | String addressStr = sdp.getConnection().getAddress(); |
| | | |
| | | logger.info("[上级点播]用户:{}, 通道:{}, 地址:{}:{}, ssrc:{}", username, channelId, addressStr, port, ssrc); |
| | | Device device = null; |
| | |
| | | return; |
| | | } |
| | | SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, |
| | | device.getDeviceId(), channelId, |
| | | mediaTransmissionTCP, platform.isRtcp()); |
| | | device.getDeviceId(), channelId, mediaTransmissionTCP, platform.isRtcp()); |
| | | |
| | | if (tcpActive != null) { |
| | | sendRtpItem.setTcpActive(tcpActive); |
| | |
| | | |
| | | try { |
| | | // 超时未收到Ack应该回复bye,当前等待时间为10秒 |
| | | dynamicTask.startDelay(callIdHeader.getCallId(), () -> { |
| | | logger.info("Ack 等待超时"); |
| | | mediaServerService.releaseSsrc(mediaServerItemInUSe.getId(), sendRtpItem.getSsrc()); |
| | | // 回复bye |
| | | try { |
| | | cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId()); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); |
| | | } |
| | | }, 60 * 1000); |
| | | responseSdpAck(request, content.toString(), platform); |
| | | if (userSetting.getPushStreamAfterAck()) { |
| | | dynamicTask.startDelay(callIdHeader.getCallId(), () -> { |
| | | logger.info("Ack 等待超时"); |
| | | mediaServerService.releaseSsrc(mediaServerItemInUSe.getId(), sendRtpItem.getSsrc()); |
| | | // 回复bye |
| | | try { |
| | | cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId()); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); |
| | | } |
| | | }, 60 * 1000); |
| | | } |
| | | |
| | | SIPResponse sipResponse = responseSdpAck(request, content.toString(), platform); |
| | | if (!userSetting.getPushStreamAfterAck()) { |
| | | playService.startPushStream(sendRtpItem, sipResponse, platform, request.getCallIdHeader()); |
| | | } |
| | | } catch (SipException e) { |
| | | e.printStackTrace(); |
| | | } catch (InvalidArgumentException e) { |
| | |
| | | if ("Playback".equalsIgnoreCase(sessionName)) { |
| | | sendRtpItem.setPlayType(InviteStreamType.PLAYBACK); |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, device.isSsrcCheck(), true); |
| | | sendRtpItem.setStreamId(ssrcInfo.getStream()); |
| | | sendRtpItem.setStream(ssrcInfo.getStream()); |
| | | // 写入redis, 超时时回复 |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), |
| | |
| | | } |
| | | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false); |
| | | logger.info(JSONObject.toJSONString(ssrcInfo)); |
| | | sendRtpItem.setStreamId(ssrcInfo.getStream()); |
| | | sendRtpItem.setStream(ssrcInfo.getStream()); |
| | | sendRtpItem.setSsrc(ssrc.equals(ssrcDefault) ? ssrcInfo.getSsrc() : ssrc); |
| | | |
| | | // 写入redis, 超时时回复 |
| | |
| | | redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), finalChannelId, callIdHeader.getCallId(), null); |
| | | }); |
| | | } else { |
| | | sendRtpItem.setStreamId(playTransaction.getStream()); |
| | | sendRtpItem.setStream(playTransaction.getStream()); |
| | | // 写入redis, 超时时回复 |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("app", sendRtpItem.getApp()); |
| | | jsonObject.put("stream", sendRtpItem.getStreamId()); |
| | | jsonObject.put("stream", sendRtpItem.getStream()); |
| | | hookEvent.response(mediaServerItem, jsonObject); |
| | | } |
| | | } |
| | |
| | | if (streamReady) { |
| | | // 自平台内容 |
| | | SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, |
| | | gbStream.getApp(), gbStream.getStream(), channelId, |
| | | mediaTransmissionTCP, platform.isRtcp()); |
| | | gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp()); |
| | | |
| | | if (sendRtpItem == null) { |
| | | logger.warn("服务器端口资源不足"); |
| | |
| | | if (streamReady) { |
| | | // 自平台内容 |
| | | SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, |
| | | gbStream.getApp(), gbStream.getStream(), channelId, |
| | | mediaTransmissionTCP, platform.isRtcp()); |
| | | gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp()); |
| | | |
| | | if (sendRtpItem == null) { |
| | | logger.warn("服务器端口资源不足"); |
| | |
| | | // 发送redis消息 |
| | | redisGbPlayMsgListener.sendMsg(streamPushItem.getServerId(), streamPushItem.getMediaServerId(), |
| | | streamPushItem.getApp(), streamPushItem.getStream(), addressStr, port, ssrc, requesterId, |
| | | channelId, mediaTransmissionTCP, platform.isRtcp(), null, responseSendItemMsg -> { |
| | | channelId, mediaTransmissionTCP, platform.isRtcp(),null, responseSendItemMsg -> { |
| | | SendRtpItem sendRtpItem = responseSendItemMsg.getSendRtpItem(); |
| | | if (sendRtpItem == null || responseSendItemMsg.getMediaServerItem() == null) { |
| | | logger.warn("服务器端口资源不足"); |
| | |
| | | content.append("f=\r\n"); |
| | | |
| | | try { |
| | | return responseSdpAck(request, content.toString(), platform); |
| | | SIPResponse sipResponse = responseSdpAck(request, content.toString(), platform); |
| | | if (!userSetting.getPushStreamAfterAck()) { |
| | | playService.startPushStream(sendRtpItem, sipResponse, platform, request.getCallIdHeader()); |
| | | } |
| | | return sipResponse; |
| | | } catch (SipException e) { |
| | | e.printStackTrace(); |
| | | } catch (InvalidArgumentException e) { |
| | |
| | | |
| | | // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备) |
| | | Device device = redisCatchStorage.getDevice(requesterId); |
| | | AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(requesterId, channelId); |
| | | if (audioBroadcastCatch == null) { |
| | | AudioBroadcastCatch broadcastCatch = audioBroadcastManager.get(requesterId, channelId); |
| | | if (broadcastCatch == null) { |
| | | logger.warn("来自设备的Invite请求非语音广播,已忽略,requesterId: {}/{}", requesterId, channelId); |
| | | try { |
| | | responseAck(request, Response.FORBIDDEN); |
| | |
| | | } |
| | | if (device != null) { |
| | | logger.info("收到设备" + requesterId + "的语音广播Invite请求"); |
| | | |
| | | String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + device.getDeviceId() + broadcastCatch.getChannelId(); |
| | | dynamicTask.stop(key); |
| | | try { |
| | | responseAck(request, Response.TRYING); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | return; |
| | | } |
| | | String contentString = new String(request.getRawContent()); |
| | | // jainSip不支持y=字段, 移除移除以解析。 |
| | |
| | | responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] invite 不支持的媒体格式: {}", e.getMessage()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | return; |
| | | } |
| | | return; |
| | | } |
| | | String addressStr = sdp.getOrigin().getAddress(); |
| | | logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", requesterId, addressStr, port, ssrc); |
| | | logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc, |
| | | mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP"); |
| | | |
| | | MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device); |
| | | MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem(); |
| | | if (mediaServerItem == null) { |
| | | logger.warn("未找到可用的zlm"); |
| | | logger.warn("未找到语音喊话使用的zlm"); |
| | | try { |
| | | responseAck(request, Response.BUSY_HERE); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | } |
| | | return; |
| | | } |
| | | logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, ssrc, |
| | | mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP", sdp.getSessionName().getValue()); |
| | | |
| | | SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, |
| | | device.getDeviceId(), audioBroadcastCatch.getChannelId(), |
| | | device.getDeviceId(), broadcastCatch.getChannelId(), |
| | | mediaTransmissionTCP, false); |
| | | |
| | | if (sendRtpItem == null) { |
| | |
| | | responseAck(request, Response.BUSY_HERE); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage()); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | return; |
| | | } |
| | | return; |
| | | } |
| | | sendRtpItem.setTcp(mediaTransmissionTCP); |
| | | if (tcpActive != null) { |
| | | sendRtpItem.setTcpActive(tcpActive); |
| | | } |
| | | String app = "broadcast"; |
| | | String stream = device.getDeviceId() + "_" + audioBroadcastCatch.getChannelId(); |
| | | |
| | | |
| | | CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); |
| | | sendRtpItem.setPlayType(InviteStreamType.PLAY); |
| | | sendRtpItem.setPlayType(InviteStreamType.BROADCAST); |
| | | sendRtpItem.setCallId(callIdHeader.getCallId()); |
| | | sendRtpItem.setPlatformId(requesterId); |
| | | sendRtpItem.setStatus(1); |
| | | sendRtpItem.setApp(app); |
| | | sendRtpItem.setStreamId(stream); |
| | | sendRtpItem.setApp(broadcastCatch.getApp()); |
| | | sendRtpItem.setStream(broadcastCatch.getStream()); |
| | | sendRtpItem.setPt(8); |
| | | sendRtpItem.setUsePs(false); |
| | | sendRtpItem.setRtcp(false); |
| | | sendRtpItem.setOnlyAudio(true); |
| | | sendRtpItem.setTcp(mediaTransmissionTCP); |
| | | if (tcpActive != null) { |
| | | sendRtpItem.setTcpActive(tcpActive); |
| | | } |
| | | |
| | | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| | | |
| | | Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream); |
| | | Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream()); |
| | | if (streamReady) { |
| | | SIPResponse sipResponse = sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, ssrc); |
| | | // 添加事务信息 |
| | | streamSession.put(device.getDeviceId(), audioBroadcastCatch.getChannelId(), request.getCallIdHeader().getCallId() |
| | | , stream, sendRtpItem.getSsrc(), mediaServerItem.getId(), sipResponse, VideoStreamSessionManager.SessionType.broadcast ); |
| | | sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, ssrc); |
| | | }else { |
| | | logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", app, stream); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); |
| | | logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", broadcastCatch.getApp(), broadcastCatch.getStream()); |
| | | try { |
| | | responseAck(request, Response.GONE); |
| | | } catch (SipException | InvalidArgumentException | ParseException e) { |
| | | logger.error("[命令发送失败] 语音通话 回复410失败, {}", e.getMessage()); |
| | | return; |
| | | } |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | } |
| | | } catch (SdpException e) { |
| | | logger.error("[SDP解析异常]", e); |
| | | playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId()); |
| | | } |
| | | } else { |
| | | logger.warn("来自无效设备/平台的请求"); |
| | |
| | | audioBroadcastCatch.setSipTransactionInfoByRequset(sipResponse); |
| | | audioBroadcastManager.update(audioBroadcastCatch); |
| | | |
| | | // 开启发流,大华在收到200OK后就会开始建立连接 |
| | | if (!userSetting.getPushStreamAfterAck()) { |
| | | playService.startPushStream(sendRtpItem, sipResponse, parentPlatform, request.getCallIdHeader()); |
| | | } |
| | | |
| | | } catch (SipException | InvalidArgumentException | ParseException | SdpParseException e) { |
| | | logger.error("[命令发送失败] 语音对讲 回复200OK(SDP): {}", e.getMessage()); |
| | | logger.error("[命令发送失败] 语音喊话 回复200OK(SDP): {}", e.getMessage()); |
| | | } |
| | | return sipResponse; |
| | | } |