package com.yfd.monitor.gdw2019.transmit.event.request.impl;

import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson2.JSONObject;
import com.yfd.monitor.common.StreamInfo;
import com.yfd.monitor.conf.DynamicTask;
import com.yfd.monitor.conf.UserSetting;
import com.yfd.monitor.conf.exception.ControllerException;
import com.yfd.monitor.gdw2019.bean.*;
import com.yfd.monitor.gdw2019.event.SipSubscribe;
import com.yfd.monitor.gdw2019.session.SSRCFactory;
import com.yfd.monitor.gdw2019.session.VideoStreamSessionManager;
import com.yfd.monitor.gdw2019.transmit.SIPProcessorObserver;
import com.yfd.monitor.gdw2019.transmit.SIPSender;
import com.yfd.monitor.gdw2019.transmit.callback.DeferredResultHolder;
import com.yfd.monitor.gdw2019.transmit.callback.RequestMessage;
import com.yfd.monitor.gdw2019.transmit.cmd.impl.SIPCommander;
import com.yfd.monitor.gdw2019.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.yfd.monitor.gdw2019.transmit.event.request.ISIPRequestProcessor;
import com.yfd.monitor.gdw2019.transmit.event.request.SIPRequestProcessorParent;
import com.yfd.monitor.gdw2019.utils.SipUtils;
import com.yfd.monitor.gdw2019.utils.StreamPusher;
import com.yfd.monitor.media.bean.MediaServer;
import com.yfd.monitor.media.zlm.ZLMMediaListManager;
import com.yfd.monitor.media.zlm.ZLMRTPServerFactory;
import com.yfd.monitor.media.zlm.ZlmHttpHookSubscribe;
import com.yfd.monitor.media.zlm.dto.HookSubscribeFactory;
import com.yfd.monitor.media.zlm.dto.HookSubscribeForStreamChange;
import com.yfd.monitor.media.zlm.dto.MediaServerItem;
import com.yfd.monitor.media.zlm.dto.StreamPushItem;
import com.yfd.monitor.service.*;
import com.yfd.monitor.service.bean.ErrorCallback;
import com.yfd.monitor.service.bean.InviteErrorCode;
import com.yfd.monitor.service.bean.MessageForPushChannel;
import com.yfd.monitor.service.bean.SSRCInfo;
import com.yfd.monitor.service.redisMsg.RedisGbPlayMsgListener;
import com.yfd.monitor.service.redisMsg.RedisPushStreamResponseListener;
import com.yfd.monitor.storager.IRedisCatchStorage;
import com.yfd.monitor.storager.IVideoManagerStorage;
import com.yfd.monitor.storager.dao.DeviceChannelMapper;
import com.yfd.monitor.storager.dao.dto.User;
import com.yfd.monitor.utils.DateUtil;
import com.yfd.monitor.vmanager.bean.DeferredResultEx;
import com.yfd.monitor.vmanager.bean.ErrorCode;
import com.yfd.monitor.vmanager.bean.StreamContent;
import com.yfd.monitor.vmanager.bean.WVPResult;
import gov.nist.javax.sdp.TimeDescriptionImpl;
import gov.nist.javax.sdp.fields.TimeField;
import gov.nist.javax.sip.header.Via;
import gov.nist.javax.sip.header.ViaList;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;

import javax.sdp.*;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.SipException;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.time.Instant;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SIP命令类型： INVITE请求
 */
@SuppressWarnings("rawtypes")
@Component
public class InviteRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {

    private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class);

    private final String method = "INVITE";

    @Autowired
    private SIPCommanderFroPlatform cmderFroPlatform;

    @Autowired
    private IVideoManagerStorage storager;

    @Autowired
    private IStreamPushService streamPushService;
    @Autowired
    private IStreamProxyService streamProxyService;

    @Autowired
    private IRedisCatchStorage redisCatchStorage;

    @Autowired
    private SSRCFactory ssrcFactory;

    @Autowired
    private DynamicTask dynamicTask;

    @Autowired
    private RedisPushStreamResponseListener redisPushStreamResponseListener;

    @Autowired
    private IPlayService playService;

    @Autowired
    private SIPCommander cmder;

    @Autowired
    private SIPSender sipSender;

    @Autowired
    private ZLMRTPServerFactory zlmrtpServerFactory;

    @Autowired
    private IMediaServerService mediaServerService;

    @Autowired
    private ZlmHttpHookSubscribe zlmHttpHookSubscribe;

    @Autowired
    private SIPProcessorObserver sipProcessorObserver;

    @Autowired
    private VideoStreamSessionManager sessionManager;

    @Autowired
    private UserSetting userSetting;

    @Autowired
    private ZLMMediaListManager mediaListManager;

    @Autowired
    private RedisGbPlayMsgListener redisGbPlayMsgListener;

    @Autowired
    private StreamPusher streamPusher;

    @Autowired
    private IUserService userService;

    @Autowired
    private DeviceChannelMapper deviceChannelMapper;

    @Autowired
    private DeferredResultHolder resultHolder;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 添加消息处理的订阅
        sipProcessorObserver.addRequestProcessor(method, this);
    }

    /**
     * 处理invite请求
     *
     * @param evt 请求消息
     */
    @Override
    public void process(RequestEvent evt) {
        try {
            SIPRequest request = (SIPRequest) evt.getRequest();
            String deviceId = SipUtils.getChannelIdFromRequest(request);
            String requesterId = SipUtils.getUserIdFromFromHeader(request);
            CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
            logger.error("=================处理invite请求==================" + request.toString());
            if (requesterId == null || deviceId == null) {
                logger.info("无法从FromHeader的Address中获取到平台ID,或者通道ID，返回400");
                // 参数不全， 发400，请求错误
                try {
                    responseAck(request, Response.BAD_REQUEST);
                } catch (SipException | InvalidArgumentException | ParseException e) {
                    logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage());
                }
                return;
            }

            try {
                //回复收到，进行中
                responseAck(request, Response.TRYING);
//                responseAck(request, Response.RINGING);
            } catch (SipException | InvalidArgumentException | ParseException e) {
                logger.error("[命令发送失败] invite TRYING: {}", e.getMessage());
            }
            Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, deviceId);
            List<DeviceChannel> deviceChannels = deviceChannelMapper.queryAllChannels(device.getDeviceId());
            MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device);

            String channelId = "";
            if (deviceChannels.size() > 0) {
                DeviceChannel deviceChannel = deviceChannels.get(0);
                channelId = deviceChannel.getChannelId();
            }
            String streamId = null;
            if (mediaServerItem.isRtpEnable()) {
                streamId = String.format("%s_%s", device.getDeviceId(), channelId);
            }
            //            SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null,
            //            device.isSsrcCheck(), false, 0, false, device.getStreamModeForParam());
            try {

                // 解析sdp消息, 使用jainsip 自带的sdp解析方式
                String contentString = new String(request.getRawContent());
                Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString);
                logger.error("===========================================================gb28181Sdp" + gb28181Sdp.toString());
                SessionDescription sdp = gb28181Sdp.getBaseSdp();
                logger.error("===========================================================sdp" + sdp.toString());
                String sessionName = sdp.getSessionName().getValue();
                String ssrc;
                if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) {
                    // 上级平台点播时不使用上级平台指定的ssrc，使用自定义的ssrc，参考国标文档-点播外域设备媒体流SSRC处理方式
                    ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) :
                            ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
                } else {
                    ssrc = gb28181Sdp.getSsrc();
                }
                ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
                logger.error("============================================sessionName" + sessionName);
                if (sessionName.equals("Play")) {
                    logger.error("===========================================================收到视频调阅");
                    mediaServerItem.setType("zlm");
                    String addressStr;
                    if (StringUtils.isEmpty(platform.getServerIP())) {
                        addressStr = sdp.getConnection().getAddress();
                    } else {
                        addressStr = platform.getServerIP();
                    }
                    //  获取支持的格式
                    Vector mediaDescriptions = sdp.getMediaDescriptions(true);
                    // 查看是否支持PS 负载96
                    //String ip = null;
                    int port = -1;
                    boolean mediaTransmissionTCP = false;
                    Boolean tcpActive = null;
                    for (Object description : mediaDescriptions) {
                        MediaDescription mediaDescription = (MediaDescription) description;
                        Media media = mediaDescription.getMedia();

                        Vector mediaFormats = media.getMediaFormats(false);
//                        if (mediaFormats.contains("96")) {
                        if (mediaFormats.contains("100")||mediaFormats.contains("108")) {
                            port = media.getMediaPort();
                            //String mediaType = media.getMediaType();
                            String protocol = media.getProtocol();

                            // 区分TCP发流还是udp， 当前默认udp
                            if ("TCP/RTP/AVP".equalsIgnoreCase(protocol)) {
                                String setup = mediaDescription.getAttribute("setup");
                                if (setup != null) {
                                    mediaTransmissionTCP = true;
                                    if ("active".equalsIgnoreCase(setup)) {
                                        tcpActive = true;
                                    } else if ("passive".equalsIgnoreCase(setup)) {
                                        tcpActive = false;
                                    }
                                }
                            }
                            break;
                        }
                    }
//                    ViaList viaHeaders = request.getViaHeaders();
//                    for (Via viaHeader : viaHeaders) {
//                        System.out.println("----------viaHeader------------"+viaHeader.toString());
//                        if(viaHeader.getRPort()>0){
//                            port=viaHeader.getRPort();
//                        }
//                    }
                    System.out.println("----------port------------"+port);
                    if (port == -1) {
                        logger.info("不支持的媒体格式，返回415");
                        // 回复不支持的格式
                        try {
                            // 不支持的格式，发415
                            responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE);
                        } catch (SipException | InvalidArgumentException | ParseException e) {
                            logger.error("[命令发送失败] invite 不支持的格式: {}", e.getMessage());
                        }
                        return;
                    }
//                    String username = sdp.getOrigin().getUsername();
//                    String streamTypeStr = null;
//                    if (mediaTransmissionTCP) {
//                        if (tcpActive) {
//                            streamTypeStr = "TCP-ACTIVE";
//                        } else {
//                            streamTypeStr = "TCP-PASSIVE";
//                        }
//                    } else {
//                        streamTypeStr = "UDP";
//                    }
//                    SendRtpItem sendRtpItem = mediaServerService.createSendRtpItem(mediaServerItem, addressStr, port,
//                            ssrc, requesterId, device.getDeviceId(), channelId, mediaTransmissionTCP,
//                            platform.isRtcp());
                    SendRtpItem sendRtpItem = mediaServerService.createSendRtpItem(mediaServerItem, addressStr, port,
                            ssrc, requesterId, device.getDeviceId(), channelId, mediaTransmissionTCP,
                            platform.isRtcp());
                    String ptName="PS";
                    int pt=96;
                    if (contentString.contains("H264")) {
                        sendRtpItem.setPt(100);
                        ptName="H264";
                        pt=100;
                    }
                    if (contentString.contains("H265")) {
                        pt=108;
                        sendRtpItem.setPt(108);
                        ptName="H265";
                    }
//                    sendRtpItem.setRtcp(true);
                    System.out.println("==================sendRtpItem=================" + sendRtpItem.toString());
                    if (sendRtpItem == null) {
                        logger.warn("服务器端口资源不足");
                        try {
                            responseAck(request, Response.BUSY_HERE);
                        } catch (SipException | InvalidArgumentException | ParseException e) {
                            logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
                        }
                        return;
                    }
                    if (tcpActive != null) {
                        sendRtpItem.setTcpActive(tcpActive);
                    }
                    sendRtpItem.setRtcp(true);
                    sendRtpItem.setCallId(callIdHeader.getCallId());
                    sendRtpItem.setPlayType("Play".equalsIgnoreCase(sessionName) ? InviteStreamType.PLAY :
                            InviteStreamType.PLAYBACK);
                    Long startTime = null;
                    Long stopTime = null;
                    Instant start = null;
                    Instant end = null;
                    if (sdp.getTimeDescriptions(false) != null && sdp.getTimeDescriptions(false).size() > 0) {
                        TimeDescriptionImpl timeDescription =
                                (TimeDescriptionImpl) (sdp.getTimeDescriptions(false).get(0));
                        TimeField startTimeFiled = (TimeField) timeDescription.getTime();
                        startTime = startTimeFiled.getStartTime();
                        stopTime = startTimeFiled.getStopTime();

                        start = Instant.ofEpochSecond(startTime);
                        end = Instant.ofEpochSecond(stopTime);
                    }
                    Long finalStartTime = startTime;
                    Long finalStopTime = stopTime;
                    String finalChannelId3 = channelId;
                    sendRtpItem.setApp("rtp");
                    String finalChannelId6 = channelId;
                    System.out.println("=====================device.getDeviceId()=======================" + device.getDeviceId() + "===" + channelId);
                    String finalPtName = ptName;
                    int finalPt = pt;
                    playService.play(mediaServerItem, device.getDeviceId(), channelId, (mediaServerItemInUse, response) -> {

                        StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), finalChannelId6);
                        MediaServerItem mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
                        logger.error("[上级Invite]下级已经开始推流。 回复200OK(SDP)， {}/{}", streamInfo.getApp(),
                                streamInfo.getStream());
                        //     * 0 等待设备推流上来
                        //     * 1 下级已经推流，等待上级平台回复ack
                        //     * 2 推流中
                        sendRtpItem.setStatus(1);
                        redisCatchStorage.updateSendRTPSever(sendRtpItem);
                        String sdpIp = mediaServerItemInUSe.getSdpIp();
                        if (!ObjectUtils.isEmpty(platform.getServerIP())) {
                            sdpIp = platform.getServerIP();
                        }
                        StringBuffer content = new StringBuffer(200);
                        content.append("v=0\r\n");
                        content.append("o=- 0 0 IN IP4 " + sdpIp + "\r\n");
                        content.append("s=" + sessionName + "\r\n");
                        content.append("c=IN IP4 " + sdpIp + "\r\n");
//                        if ("Playback".equalsIgnoreCase(sessionName)) {
//                            content.append("t=" + finalStartTime + " " + finalStopTime + "\r\n");
//                        } else {
//                            content.append("t=0 0\r\n");
//                        }
                        int localPort = sendRtpItem.getLocalPort();
                        if (localPort == 0) {
                            // 非严格模式端口不统一, 增加兼容性，修改为一个不为0的端口
                            localPort = new Random().nextInt(65535) + 1;
                        }
                        if (sendRtpItem.isTcp()) {
                            content.append("m=video " + localPort + " TCP/RTP/AVP 96\r\n");
                            if (!sendRtpItem.isTcpActive()) {
                                content.append("a=setup:active\r\n");
                            } else {
                                content.append("a=setup:passive\r\n");
                            }
                        } else {
                            content.append("m=video " + localPort + " RTP/AVP "+ finalPt +"\r\n");
                        }

                        content.append("a=mime:\r\n");
                        content.append("a=rtpmap:"+ finalPt +" "+ finalPtName +"/90000\r\n");
//                        content.append("a=fmtp:100 CIF=1\r\n");
                        content.append("a=fmtp:"+ finalPt +" profile-level-id=420028;sprop-parameter-sets=Z0IAKOkBQHsg,aM44gA==\r\n");
                        content.append("y=" + sendRtpItem.getSsrc() + "\r\n");
                        content.append("a=sendonly\r\n");
                        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);
                            // tcp主动模式，回复sdp后开启监听
                            if (sendRtpItem.isTcpActive()) {
                                MediaServerItem mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
                                try {
                                    mediaServerService.startSendRtpPassive(mediaServer, platform, sendRtpItem, 5);
                                } catch (ControllerException e) {
                                }
                            }
                        } catch (SipException | InvalidArgumentException | ParseException e) {
                            logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
                        }

                    }, event -> {

                        logger.error(String.format("点播失败， 错误码： %s, %s", event.statusCode, event.msg));
                    }, null);
                } else if (sessionName.equals("Talk")) {//播放语言广播
                    SSRCInfo ssrcInfo = null;
                    try {
                        responseSdpAck(request, contentString, platform);
                    } catch (SipException e) {
                        e.printStackTrace();
                    } catch (InvalidArgumentException e) {
                        e.printStackTrace();
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    //发起语音广播
                    String parent_rtsp = sdp.getURI().toString().replaceAll("\r\n", "");  //推流到上级单位的地址
                    String finalStreamId = streamId;
                    String finalChannelId = channelId;
                    cmder.audioBroadcastCmd("2", device, channelId, contentString, mediaServerItem, ssrcInfo, (event) -> {
                        SendRtpItem sendRtpItem = new SendRtpItem();
                        sendRtpItem.setPlatformId(platform.getServerGBId());
                        sendRtpItem.setMediaServerId(mediaServerItem.getId());
                        sendRtpItem.setChannelId(finalChannelId);
                        sendRtpItem.setStreamId(finalStreamId);
                        sendRtpItem.setSsrc(ssrc);
                        sendRtpItem.setDeviceId(device.getDeviceId());
                        sendRtpItem.setPlayType(InviteStreamType.TALK);
                        sendRtpItem.setCallId(callIdHeader.getCallId());
                        redisCatchStorage.updateSendRTPSever(sendRtpItem);
                        String ffmpeg_path = userSetting.getFfmpegpath();
                        String video_rtsp = String.format("rtsp://%s:554/rtp/%s_%s", platform.getDeviceIp(), device.getDeviceId(), finalChannelId);
                        streamPusher.pushStreamToParent(ffmpeg_path, video_rtsp, parent_rtsp);

                    });
                } else if (sessionName.equals("Playback")) {//录像回放
                    SSRCInfo ssrcInfo = null;
                    try {
                        responseSdpAck(request, contentString, platform);
                    } catch (SipException e) {
                        e.printStackTrace();
                    } catch (InvalidArgumentException e) {
                        e.printStackTrace();
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    //发起语音广播
                    String parent_rtsp = sdp.getURI().toString().replaceAll("\r\n", "");  //推流到上级单位的地址
                    String finalStreamId = streamId;
                    String finalChannelId2 = channelId;
                    cmder.audioBroadcastCmd("2", device, channelId, contentString, mediaServerItem, ssrcInfo, (event) -> {
                        SendRtpItem sendRtpItem = new SendRtpItem();
                        sendRtpItem.setPlatformId(platform.getServerGBId());
                        sendRtpItem.setMediaServerId(mediaServerItem.getId());
                        sendRtpItem.setChannelId(finalChannelId2);
                        sendRtpItem.setStreamId(finalStreamId);
                        sendRtpItem.setSsrc(ssrc);
                        sendRtpItem.setDeviceId(device.getDeviceId());
                        sendRtpItem.setPlayType(InviteStreamType.TALK);
                        sendRtpItem.setCallId(callIdHeader.getCallId());
                        redisCatchStorage.updateSendRTPSever(sendRtpItem);
                        String ffmpeg_path = userSetting.getFfmpegpath();
                        String video_rtsp = String.format("rtsp://%s:554/rtp/%s_%s", platform.getDeviceIp(), device.getDeviceId(), finalChannelId2);
                        streamPusher.pushStreamToParent(ffmpeg_path, video_rtsp, parent_rtsp);

                    });
                } else {
                    //发起录像回放
                    Long startTime = null;
                    Long stopTime = null;
                    Instant start = null;
                    Instant end = null;
                    if (sdp.getTimeDescriptions(false) != null && sdp.getTimeDescriptions(false).size() > 0) {
                        TimeDescriptionImpl timeDescription = (TimeDescriptionImpl) (sdp.getTimeDescriptions(false).get(0));
                        TimeField startTimeFiled = (TimeField) timeDescription.getTime();
                        startTime = startTimeFiled.getStartTime();
                        stopTime = startTimeFiled.getStopTime();
                        start = Instant.ofEpochSecond(startTime);
                        end = Instant.ofEpochSecond(stopTime);
                    }
                    SipSubscribe.Event errorEvent = ((event) -> {
                        // 未知错误。直接转发设备点播的错误
                        try {
                            Response response = getMessageFactory().createResponse(event.statusCode, evt.getRequest());
                            sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
                        } catch (ParseException | SipException e) {
                            logger.error("未处理的异常 ", e);
                        }
                    });
                    //  获取支持的格式
                    Vector mediaDescriptions = sdp.getMediaDescriptions(true);
                    // 查看是否支持PS 负载96
                    //String ip = null;
                    int port = -1;
                    boolean mediaTransmissionTCP = false;
                    Boolean tcpActive = null;
                    for (Object description : mediaDescriptions) {
                        MediaDescription mediaDescription = (MediaDescription) description;
                        Media media = mediaDescription.getMedia();

                        Vector mediaFormats = media.getMediaFormats(false);
                        if (mediaFormats.contains("100")) {
                            port = media.getMediaPort();
                            //String mediaType = media.getMediaType();
                            String protocol = media.getProtocol();

                            // 区分TCP发流还是udp， 当前默认udp
                            if ("RTP/AVP/TCP".equalsIgnoreCase(protocol)) {
                                String setup = mediaDescription.getAttribute("setup");
                                if (setup != null) {
                                    mediaTransmissionTCP = true;
                                    if ("active".equalsIgnoreCase(setup)) {
                                        tcpActive = true;
                                    } else if ("passive".equalsIgnoreCase(setup)) {
                                        tcpActive = false;
                                    }
                                }
                            }
                            break;
                        }
                    }
                    if (port == -1) {
                        logger.info("不支持的媒体格式，返回415");
                        // 回复不支持的格式
                        try {
                            // 不支持的格式，发415
                            responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE);
                        } catch (SipException | InvalidArgumentException | ParseException e) {
                            logger.error("[命令发送失败] invite 不支持的格式: {}", e.getMessage());
                        }
                        return;
                    }
                    String addressStr = sdp.getConnection().getAddress();

                    SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
                            device.getDeviceId(), channelId, mediaTransmissionTCP, platform.isRtcp());

                    if (tcpActive != null) {
                        sendRtpItem.setTcpActive(tcpActive);
                    }
                    if (sendRtpItem == null) {
                        logger.warn("服务器端口资源不足");
                        try {
                            responseAck(request, Response.BUSY_HERE);
                        } catch (SipException | InvalidArgumentException | ParseException e) {
                            logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
                        }
                        return;
                    }
                    sendRtpItem.setCallId(callIdHeader.getCallId());
                    sendRtpItem.setPlayType(InviteStreamType.PLAYBACK);

                    Long finalStartTime = startTime;
                    Long finalStopTime = stopTime;
                    boolean finalMediaTransmissionTCP = mediaTransmissionTCP;
                    String finalChannelId4 = channelId;
                    ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON) -> {
                        String app = responseJSON.getString("app");
                        String stream = responseJSON.getString("stream");
                        logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP)， {}/{}", app, stream);
                        //     * 0 等待设备推流上来
                        //     * 1 下级已经推流，等待上级平台回复ack
                        //     * 2 推流中
                        sendRtpItem.setStatus(1);
                        redisCatchStorage.updateSendRTPSever(sendRtpItem);

                        StringBuffer content = new StringBuffer(200);
                        content.append("v=0\r\n");
                        content.append("o=" + finalChannelId4 + " 0 0 IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n");
                        content.append("s=Playback\r\n");
                        content.append("u=" + sendRtpItem.getIp() + ":" + sendRtpItem.getPort() + "/" + sendRtpItem.getApp() + "/" + sendRtpItem.getStreamId() + "\r\n");
                        content.append("c=IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n");
                        content.append("t=" + finalStartTime + " " + finalStopTime + "\r\n");
                        int localPort = sendRtpItem.getLocalPort();
                        if (localPort == 0) {
                            // 非严格模式端口不统一, 增加兼容性，修改为一个不为0的端口
                            localPort = new Random().nextInt(65535) + 1;
                        }
                        content.append("y=" + sendRtpItem.getSsrc() + "\r\n");
                        content.append("a=rtpmap:100 H264/90000\r\n");
                        content.append("a=fmtp:100 profile-level-id=420028;sprop-parameter-sets=Z0IAKOkBQHsg,aM44gA==\r\n");
                        if (finalMediaTransmissionTCP) {
                            content.append("m=video " + localPort + "  RTP/AVP/TCP 100\r\n");
                            content.append("a=setup:active\r\n");
                            content.append("a=connection:new\r\n");
                        } else {
                            content.append("m=video " + localPort + " RTP/AVP 100\r\n");
                        }

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

                        } catch (SipException | InvalidArgumentException | ParseException e) {
                            logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
                        }
                    };
                    SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null,
                            device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
                    String finalChannelId1 = channelId;
                    playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId,
                            DateUtil.formatter.format(start),
                            DateUtil.formatter.format(end), null, result -> {
                                if (result.getCode() != 0) {
                                    logger.warn("录像回放失败");
                                    if (result.getEvent() != null) {
                                        errorEvent.response(result.getEvent());
                                    }
                                    redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), finalChannelId1, callIdHeader.getCallId(), null);
                                    try {
                                        responseAck(request, Response.REQUEST_TIMEOUT);
                                    } catch (SipException | InvalidArgumentException | ParseException e) {
                                        logger.error("[命令发送失败] 国标级联 录像回放 发送REQUEST_TIMEOUT: {}", e.getMessage());
                                    }
                                } else {
                                    if (result.getMediaServerItem() != null) {
                                        hookEvent.response(result.getMediaServerItem(), result.getResponse());
                                    }
                                }
                            });
                }

            } catch (InvalidArgumentException e) {
                e.printStackTrace();
            } catch (SipException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("系统转发错误！", e);
        }

    }

    private static String extractHeader(String sipMessage, String headerName) {
        String[] headers = sipMessage.split("\r\n");
        for (String header : headers) {
            if (header.trim().startsWith(headerName)) {
                return header.trim();
            }
        }
        return null;
    }

    private static String extractTagFromFromHeader(String fromHeader) {
        Pattern pattern = Pattern.compile(";tag=([^;]+)");
        Matcher matcher = pattern.matcher(fromHeader);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

    /**
     * 安排推流
     */
    private void pushProxyStream(RequestEvent evt, SIPRequest request, GbStream gbStream, ParentPlatform platform,
                                 CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
                                 int port, Boolean tcpActive, boolean mediaTransmissionTCP,
                                 String channelId, String addressStr, String ssrc, String requesterId) {
        Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(),
                gbStream.getStream());
        if (streamReady) {
            // 自平台内容
            SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc,
                    requesterId,
                    gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());

            if (sendRtpItem == null) {
                logger.warn("服务器端口资源不足");
                try {
                    responseAck(request, Response.BUSY_HERE);
                } catch (SipException | InvalidArgumentException | ParseException e) {
                    logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
                }
                return;
            }
            if (tcpActive != null) {
                sendRtpItem.setTcpActive(tcpActive);
            }
            sendRtpItem.setPlayType(InviteStreamType.PUSH);
            // 写入redis， 超时时回复
            sendRtpItem.setStatus(1);
            sendRtpItem.setCallId(callIdHeader.getCallId());
            sendRtpItem.setFromTag(request.getFromTag());

            SIPResponse response = sendStreamAck(mediaServerItem, request, sendRtpItem, platform, evt);
            if (response != null) {
                sendRtpItem.setToTag(response.getToTag());
            }
            redisCatchStorage.updateSendRTPSever(sendRtpItem);

        }

    }

    private void pushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
                            CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
                            int port, Boolean tcpActive, boolean mediaTransmissionTCP,
                            String channelId, String addressStr, String ssrc, String requesterId) {
        // 推流
        if (streamPushItem.isSelf()) {
            Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
            if (streamReady) {
                // 自平台内容
                SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
                        gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());

                if (sendRtpItem == null) {
                    logger.warn("服务器端口资源不足");
                    try {
                        responseAck(request, Response.BUSY_HERE);
                    } catch (SipException | InvalidArgumentException | ParseException e) {
                        logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
                    }
                    return;
                }
                if (tcpActive != null) {
                    sendRtpItem.setTcpActive(tcpActive);
                }
                sendRtpItem.setPlayType(InviteStreamType.PUSH);
                // 写入redis， 超时时回复
                sendRtpItem.setStatus(1);
                sendRtpItem.setCallId(callIdHeader.getCallId());

                sendRtpItem.setFromTag(request.getFromTag());
                SIPResponse response = sendStreamAck(mediaServerItem, request, sendRtpItem, platform, evt);
                if (response != null) {
                    sendRtpItem.setToTag(response.getToTag());
                }

                redisCatchStorage.updateSendRTPSever(sendRtpItem);

            } else {
                // 不在线 拉起
                notifyStreamOnline(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
                        mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
            }

        } else {
            // 其他平台内容
            otherWvpPushStream(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
                    mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
        }
    }

    /**
     * 通知流上线
     */
    private void notifyStreamOnline(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
                                    CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
                                    int port, Boolean tcpActive, boolean mediaTransmissionTCP,
                                    String channelId, String addressStr, String ssrc, String requesterId) {
        if ("proxy".equals(gbStream.getStreamType())) {
            // TODO 控制启用以使设备上线
            logger.info("[ app={}, stream={} ]通道未推流，启用流后开始推流", gbStream.getApp(), gbStream.getStream());
            // 监听流上线
            HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(gbStream.getApp(), gbStream.getStream(), true, "rtsp", mediaServerItem.getId());
            zlmHttpHookSubscribe.addSubscribe(hookSubscribe, (mediaServerItemInUSe, responseJSON) -> {
                String app = responseJSON.getString("app");
                String stream = responseJSON.getString("stream");
                logger.info("[上级点播]拉流代理已经就绪， {}/{}", app, stream);
                dynamicTask.stop(callIdHeader.getCallId());
                pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive,
                        mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
            });
            dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
                logger.info("[ app={}, stream={} ] 等待拉流代理流超时", gbStream.getApp(), gbStream.getStream());
                zlmHttpHookSubscribe.removeSubscribe(hookSubscribe);
            }, userSetting.getPlatformPlayTimeout());
            boolean start = streamProxyService.start(gbStream.getApp(), gbStream.getStream());
            if (!start) {
                try {
                    responseAck(request, Response.BUSY_HERE, "channel [" + gbStream.getGbId() + "] offline");
                } catch (SipException | InvalidArgumentException | ParseException e) {
                    logger.error("[命令发送失败] invite 通道未推流: {}", e.getMessage());
                }
                zlmHttpHookSubscribe.removeSubscribe(hookSubscribe);
                dynamicTask.stop(callIdHeader.getCallId());
            }


        } else if ("push".equals(gbStream.getStreamType())) {
            if (!platform.isStartOfflinePush()) {
                // 平台设置中关闭了拉起离线的推流则直接回复
                try {
                    logger.info("[上级点播] 失败，推流设备未推流，channel: {}, app: {}, stream: {}", gbStream.getGbId(), gbStream.getApp(), gbStream.getStream());
                    responseAck(request, Response.TEMPORARILY_UNAVAILABLE, "channel stream not pushing");
                } catch (SipException | InvalidArgumentException | ParseException e) {
                    logger.error("[命令发送失败] invite 通道未推流: {}", e.getMessage());
                }
                return;
            }
            // 发送redis消息以使设备上线
            logger.info("[ app={}, stream={} ]通道未推流，发送redis信息控制设备开始推流", gbStream.getApp(), gbStream.getStream());

            MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(1,
                    gbStream.getApp(), gbStream.getStream(), gbStream.getGbId(), gbStream.getPlatformId(),
                    platform.getName(), null, gbStream.getMediaServerId());
            redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);
            // 设置超时
            dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
                logger.info("[ app={}, stream={} ] 等待设备开始推流超时", gbStream.getApp(), gbStream.getStream());
                try {
                    mediaListManager.removedChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream());
                    responseAck(request, Response.REQUEST_TIMEOUT); // 超时
                } catch (SipException e) {
                    logger.error("未处理的异常 ", e);
                } catch (InvalidArgumentException e) {
                    logger.error("未处理的异常 ", e);
                } catch (ParseException e) {
                    logger.error("未处理的异常 ", e);
                }
            }, userSetting.getPlatformPlayTimeout());
            // 添加监听
            int finalPort = port;
            Boolean finalTcpActive = tcpActive;

            // 添加在本机上线的通知
            mediaListManager.addChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream(), (app, stream, serverId) -> {
                dynamicTask.stop(callIdHeader.getCallId());
                if (serverId.equals(userSetting.getServerId())) {
                    SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, finalPort, ssrc, requesterId,
                            app, stream, channelId, mediaTransmissionTCP, platform.isRtcp());

                    if (sendRtpItem == null) {
                        logger.warn("上级点时创建sendRTPItem失败，可能是服务器端口资源不足");
                        try {
                            responseAck(request, Response.BUSY_HERE);
                        } catch (SipException e) {
                            logger.error("未处理的异常 ", e);
                        } catch (InvalidArgumentException e) {
                            logger.error("未处理的异常 ", e);
                        } catch (ParseException e) {
                            logger.error("未处理的异常 ", e);
                        }
                        return;
                    }
                    if (finalTcpActive != null) {
                        sendRtpItem.setTcpActive(finalTcpActive);
                    }
                    sendRtpItem.setPlayType(InviteStreamType.PUSH);
                    // 写入redis， 超时时回复
                    sendRtpItem.setStatus(1);
                    sendRtpItem.setCallId(callIdHeader.getCallId());

                    sendRtpItem.setFromTag(request.getFromTag());
                    SIPResponse response = sendStreamAck(mediaServerItem, request, sendRtpItem, platform, evt);
                    if (response != null) {
                        sendRtpItem.setToTag(response.getToTag());
                    }
                    redisCatchStorage.updateSendRTPSever(sendRtpItem);
                } else {
                    // 其他平台内容
                    otherWvpPushStream(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
                            mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
                }
            });

            // 添加回复的拒绝或者错误的通知
            redisPushStreamResponseListener.addEvent(gbStream.getApp(), gbStream.getStream(), response -> {
                if (response.getCode() != 0) {
                    dynamicTask.stop(callIdHeader.getCallId());
                    mediaListManager.removedChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream());
                    try {
                        responseAck(request, Response.TEMPORARILY_UNAVAILABLE, response.getMsg());
                    } catch (SipException | InvalidArgumentException | ParseException e) {
                        logger.error("[命令发送失败] 国标级联 点播回复: {}", e.getMessage());
                    }
                }
            });
        }
    }

    /**
     * 来自其他wvp的推流
     */
    private void otherWvpPushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
                                    CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
                                    int port, Boolean tcpActive, boolean mediaTransmissionTCP,
                                    String channelId, String addressStr, String ssrc, String requesterId) {
        logger.info("[级联点播]直播流来自其他平台，发送redis消息");
        // 发送redis消息
        redisGbPlayMsgListener.sendMsg(streamPushItem.getServerId(), streamPushItem.getMediaServerId(),
                streamPushItem.getApp(), streamPushItem.getStream(), addressStr, port, ssrc, requesterId,
                channelId, mediaTransmissionTCP, platform.isRtcp(), null, responseSendItemMsg -> {
                    SendRtpItem sendRtpItem = responseSendItemMsg.getSendRtpItem();
                    if (sendRtpItem == null || responseSendItemMsg.getMediaServerItem() == null) {
                        logger.warn("服务器端口资源不足");
                        try {
                            responseAck(request, Response.BUSY_HERE);
                        } catch (SipException e) {
                            logger.error("未处理的异常 ", e);
                        } catch (InvalidArgumentException e) {
                            logger.error("未处理的异常 ", e);
                        } catch (ParseException e) {
                            logger.error("未处理的异常 ", e);
                        }
                        return;
                    }
                    // 收到sendItem
                    if (tcpActive != null) {
                        sendRtpItem.setTcpActive(tcpActive);
                    }
                    sendRtpItem.setPlayType(InviteStreamType.PUSH);
                    // 写入redis， 超时时回复
                    sendRtpItem.setStatus(1);
                    sendRtpItem.setCallId(callIdHeader.getCallId());

                    sendRtpItem.setFromTag(request.getFromTag());
                    SIPResponse response = sendStreamAck(responseSendItemMsg.getMediaServerItem(), request, sendRtpItem, platform, evt);
                    if (response != null) {
                        sendRtpItem.setToTag(response.getToTag());
                    }
                    redisCatchStorage.updateSendRTPSever(sendRtpItem);
                }, (wvpResult) -> {

                    // 错误
                    if (wvpResult.getCode() == RedisGbPlayMsgListener.ERROR_CODE_OFFLINE) {
                        // 离线
                        // 查询是否在本机上线了
                        StreamPushItem currentStreamPushItem = streamPushService.getPush(streamPushItem.getApp(), streamPushItem.getStream());
                        if (currentStreamPushItem.isPushIng()) {
                            // 在线状态
                            pushStream(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
                                    mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);

                        } else {
                            // 不在线 拉起
                            notifyStreamOnline(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
                                    mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
                        }
                    }
                    try {
                        responseAck(request, Response.BUSY_HERE);
                    } catch (InvalidArgumentException | ParseException | SipException e) {
                        logger.error("[命令发送失败] 国标级联 点播回复 BUSY_HERE: {}", e.getMessage());
                    }
                });
    }

    public SIPResponse sendStreamAck(MediaServerItem mediaServerItem, SIPRequest request, SendRtpItem sendRtpItem, ParentPlatform platform, RequestEvent evt) {

        StringBuffer content = new StringBuffer(200);
        content.append("v=0\r\n");
        content.append("o=" + sendRtpItem.getChannelId() + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
        content.append("s=Play\r\n");
        content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
        content.append("t=0 0\r\n");
        // 非严格模式端口不统一, 增加兼容性，修改为一个不为0的端口
        int localPort = sendRtpItem.getLocalPort();
        if (localPort == 0) {
            localPort = new Random().nextInt(65535) + 1;
        }
        content.append("m=video " + localPort + " RTP/AVP 96\r\n");
        content.append("a=sendonly\r\n");
        content.append("a=rtpmap:96 PS/90000\r\n");
        if (sendRtpItem.isTcp()) {
            content.append("a=connection:new\r\n");
            if (!sendRtpItem.isTcpActive()) {
                content.append("a=setup:active\r\n");
            } else {
                content.append("a=setup:passive\r\n");
            }
        }
        content.append("y=" + sendRtpItem.getSsrc() + "\r\n");
        content.append("f=\r\n");

        try {
            return responseSdpAck(request, content.toString(), platform);
        } catch (SipException e) {
            logger.error("未处理的异常 ", e);
        } catch (InvalidArgumentException e) {
            logger.error("未处理的异常 ", e);
        } catch (ParseException e) {
            logger.error("未处理的异常 ", e);
        }
        return null;
    }

    public void inviteFromDeviceHandle(SIPRequest request, String requesterId) {

        // 非上级平台请求，查询是否设备请求（通常为接收语音广播的设备）
        Device device = redisCatchStorage.getDevice(requesterId);
        if (device != null) {
            logger.info("收到设备" + requesterId + "的语音广播Invite请求");
            try {
                responseAck(request, Response.TRYING);
            } catch (SipException | InvalidArgumentException | ParseException e) {
                logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage());
            }
            String contentString = new String(request.getRawContent());
            // jainSip不支持y=字段， 移除移除以解析。
            String substring = contentString;
            String ssrc = "0000000404";
            int ssrcIndex = contentString.indexOf("y=");
            if (ssrcIndex > 0) {
                substring = contentString.substring(0, ssrcIndex);
                ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
            }
            ssrcIndex = substring.indexOf("f=");
            if (ssrcIndex > 0) {
                substring = contentString.substring(0, ssrcIndex);
            }
            SessionDescription sdp = null;
            try {
                sdp = SdpFactory.getInstance().createSessionDescription(substring);
                //  获取支持的格式
                Vector mediaDescriptions = sdp.getMediaDescriptions(true);
                // 查看是否支持PS 负载96
                int port = -1;
                //boolean recvonly = false;
                boolean mediaTransmissionTCP = false;
                Boolean tcpActive = null;
                for (int i = 0; i < mediaDescriptions.size(); i++) {
                    MediaDescription mediaDescription = (MediaDescription) mediaDescriptions.get(i);
                    Media media = mediaDescription.getMedia();

                    Vector mediaFormats = media.getMediaFormats(false);
                    if (mediaFormats.contains("8")) {
                        port = media.getMediaPort();
                        String protocol = media.getProtocol();
                        // 区分TCP发流还是udp， 当前默认udp
                        if ("TCP/RTP/AVP".equals(protocol)) {
                            String setup = mediaDescription.getAttribute("setup");
                            if (setup != null) {
                                mediaTransmissionTCP = true;
                                if ("active".equals(setup)) {
                                    tcpActive = true;
                                } else if ("passive".equals(setup)) {
                                    tcpActive = false;
                                }
                            }
                        }
                        break;
                    }
                }
                if (port == -1) {
                    logger.info("不支持的媒体格式，返回415");
                    // 回复不支持的格式
                    try {
                        responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式，发415
                    } catch (SipException | InvalidArgumentException | ParseException e) {
                        logger.error("[命令发送失败] invite 不支持的媒体格式，返回415， {}", e.getMessage());
                    }
                    return;
                }
                String username = sdp.getOrigin().getUsername();
                String addressStr = sdp.getConnection().getAddress();
                logger.info("设备{}请求语音流，地址：{}:{}，ssrc：{}", username, addressStr, port, ssrc);
            } catch (SdpException e) {
                logger.error("[SDP解析异常]", e);
            }


        } else {
            logger.warn("来自无效设备/平台的请求");
            try {
                responseAck(request, Response.BAD_REQUEST);// 不支持的格式，发415
            } catch (SipException | InvalidArgumentException | ParseException e) {
                logger.error("[命令发送失败] invite 来自无效设备/平台的请求， {}", e.getMessage());
            }
        }
    }

    private boolean pushStreamToParent(String from_rtsp, String parent_rtsp) {
        //todo : ffmpeg -rtsp_transport tcp -i rtsp://192.168.1.13:554/rtp/34020000001320000001_34020000001320000009 -c:v copy -c:a copy -f rtsp rtsp://192.168.1.13:554/live/232323?secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc
        return true;
    }
}
