648540858
2022-11-18 ecf84bb0f1952c4a044ff6c8aa18226b31593f3f
合并主线
28个文件已修改
581 ■■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 120 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamPush.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItemLite.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/devicePlayer.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -223,8 +223,8 @@
        }
    }
    public void setRtc(String host, int port, int sslPort, String app, String stream, String callIdParam) {
        String file = String.format("index/api/webrtc?app=%s&stream=%s&type=play%s", app, stream, callIdParam);
    public void setRtc(String host, int port, int sslPort, String app, String stream, String callIdParam, boolean isPlay) {
        String file = String.format("index/api/webrtc?app=%s&stream=%s&type=%s%s", app, stream, callIdParam, isPlay?"play":"push");
        this.rtc = new StreamURL("http", host, port, file);
        if (sslPort != 0) {
            this.rtcs = new StreamURL("https", host, sslPort, file);
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
@@ -94,9 +94,4 @@
        this.alarm = alarm;
    }
    public void getLocalIp(String deviceLocalIp) {
        if (ObjectUtils.isEmpty(deviceLocalIp)) {
        }
    }
}
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -31,7 +31,7 @@
    private Boolean logInDatebase = Boolean.TRUE;
    private Boolean usePushingAsStatus = Boolean.TRUE;
    private Boolean usePushingAsStatus = Boolean.FALSE;
    private Boolean useSourceIpAsStreamIp = Boolean.FALSE;
src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java
@@ -2,6 +2,7 @@
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -27,11 +28,20 @@
    }
    public void update(AudioBroadcastCatch audioBroadcastCatch) {
        data.put(audioBroadcastCatch.getDeviceId() + audioBroadcastCatch.getChannelId(), audioBroadcastCatch);
        if (SipUtils.isFrontEnd(audioBroadcastCatch.getDeviceId())) {
            data.put(audioBroadcastCatch.getDeviceId(), audioBroadcastCatch);
        }else {
            data.put(audioBroadcastCatch.getDeviceId() + audioBroadcastCatch.getChannelId(), audioBroadcastCatch);
        }
    }
    public void del(String deviceId, String channelId) {
        data.remove(deviceId + channelId);
        if (SipUtils.isFrontEnd(deviceId)) {
            data.remove(deviceId);
        }else {
            data.remove(deviceId + channelId);
        }
    }
    public void delByDeviceId(String deviceId) {
@@ -50,15 +60,22 @@
    public boolean exit(String deviceId, String channelId) {
        for (String key : data.keySet()) {
            if (key.equals(deviceId + channelId)) {
                return true;
            if (SipUtils.isFrontEnd(deviceId)) {
                return key.equals(deviceId);
            }else {
                return key.equals(deviceId + channelId);
            }
        }
        return false;
    }
    public AudioBroadcastCatch get(String deviceId, String channelId) {
        AudioBroadcastCatch audioBroadcastCatch = data.get(deviceId + channelId);
        AudioBroadcastCatch audioBroadcastCatch;
        if (SipUtils.isFrontEnd(deviceId)) {
            audioBroadcastCatch = data.get(deviceId);
        }else {
            audioBroadcastCatch = data.get(deviceId + channelId);
        }
        if (audioBroadcastCatch == null) {
            Stream<AudioBroadcastCatch> allAudioBroadcastCatchStreamForDevice = data.values().stream().filter(
                    audioBroadcastCatchItem -> Objects.equals(audioBroadcastCatchItem.getDeviceId(), deviceId));
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -15,6 +15,7 @@
import javax.sip.message.Message;
import javax.sip.message.Request;
import java.text.ParseException;
import javax.sip.message.Message;
import javax.sip.message.Request;
/**    
@@ -361,4 +362,5 @@
     */
    void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException;
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
@@ -318,32 +318,32 @@
    public Request createBroadcastMessageRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
        Request request = null;
        // sipuri
        SipURI requestURI = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
        SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());
        // via
        ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
        ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
        ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
        viaHeader.setRPort();
        viaHeaders.add(viaHeader);
        // from
        SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
        Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
        FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
        SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
        Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);
        FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag);
        // to
        SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
        Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
        ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
        SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());
        Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);
        ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress, toTag);
        // Forwards
        MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
        MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70);
        // ceq
        CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);
        CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);
        ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
        ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
        request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
        request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
                toHeader, viaHeaders, maxForwards, contentTypeHeader, content);
        request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
        request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil));
        return request;
    }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -19,15 +19,11 @@
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.HookSubscribeForStreamPush;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.utils.GitUtil;
import gov.nist.javax.sip.SipProviderImpl;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.GitUtil;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import org.slf4j.Logger;
@@ -41,8 +37,6 @@
import javax.sip.ResponseEvent;
import javax.sip.SipException;
import javax.sip.header.CallIdHeader;
import javax.sip.*;
import javax.sip.header.*;
import javax.sip.message.Request;
import java.text.ParseException;
@@ -77,6 +71,9 @@
    @Autowired
    private ZlmHttpHookSubscribe subscribe;
    @Autowired
    private GitUtil gitUtil;
@@ -607,8 +604,7 @@
            }
        });
        CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
                : udpSipProvider.getNewCallId();
        CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
        callIdHeader.setCallId(callId);
        HookSubscribeForStreamPush hookSubscribeForStreamPush = HookSubscribeFactory.on_publish("rtp", stream,  null, mediaServerItem.getId());
        subscribe.addSubscribe(hookSubscribeForStreamPush, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
@@ -633,7 +629,7 @@
        content.append("f=v/////a/1/8/1" + "\r\n");
        Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(), callIdHeader);
        transmitRequest(device.getTransport(), request, (e -> {
        sipSender.transmitRequest(device.getTransport(), request, (e -> {
            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
            errorEvent.response(e);
@@ -675,7 +671,7 @@
    @Override
    public synchronized void streamByeCmd(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
        Request byteRequest = headerProvider.createByteRequest(device, channelId, sipTransactionInfo);
        transmitRequest(device.getTransport(), byteRequest, null, okEvent);
        sipSender.transmitRequest(device.getTransport(), byteRequest, null, okEvent);
    }
    /**
@@ -695,10 +691,8 @@
        broadcastXml.append("<TargetID>" + channelId + "</TargetID>\r\n");
        broadcastXml.append("</Notify>\r\n");
        Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
    }
@@ -1339,8 +1333,6 @@
        logger.debug("拉框信令: " + request.toString());
        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
    }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -1,7 +1,6 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.gb28181.SipLayer;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
@@ -9,13 +8,13 @@
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
import com.genersoft.iot.vmp.utils.DateUtil;
import gov.nist.javax.sip.message.MessageFactoryImpl;
import gov.nist.javax.sip.message.SIPRequest;
import org.slf4j.Logger;
@@ -26,10 +25,10 @@
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import com.genersoft.iot.vmp.utils.DateUtil;
import javax.sip.*;
import javax.sip.header.*;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import javax.sip.header.CallIdHeader;
import javax.sip.header.WWWAuthenticateHeader;
import javax.sip.message.Request;
import java.text.ParseException;
import java.util.ArrayList;
@@ -629,21 +628,21 @@
            logger.info("[向上级发送BYE], sendRtpItem 为NULL");
            return;
        }
        if (parentPlatform == null) {
        if (platform == null) {
            logger.info("[向上级发送BYE], platform 为NULL");
            return;
        }
        logger.info("[向上级发送BYE], {}/{}", parentPlatform.getServerGBId(), sendRtpItem.getChannelId());
        logger.info("[向上级发送BYE], {}/{}", platform.getServerGBId(), sendRtpItem.getChannelId());
        String mediaServerId = sendRtpItem.getMediaServerId();
        MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
        if (mediaServerItem != null) {
            mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
            zlmrtpServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStreamId());
        }
        SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(parentPlatform, sendRtpItem);
        SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(platform, sendRtpItem);
        if (byeRequest == null) {
            logger.warn("[向上级发送bye]:无法创建 byeRequest");
        }
        sipSender.transmitRequest(parentPlatform.getDeviceIp(),byeRequest);
        sipSender.transmitRequest(platform.getDeviceIp(),byeRequest);
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
@@ -2,6 +2,7 @@
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import gov.nist.javax.sip.SipProviderImpl;
@@ -17,6 +18,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.parameters.P;
import javax.sip.*;
import javax.sip.address.Address;
@@ -93,52 +95,6 @@
        return responseAck(sipRequest, statusCode, msg, null);
    }
//    public SIPResponse responseAck(ServerTransaction serverTransaction, int statusCode, String msg, ResponseAckExtraParam responseAckExtraParam) throws SipException, InvalidArgumentException, ParseException {
//        if (serverTransaction == null) {
//            logger.warn("[回复消息] ServerTransaction 为null");
//            return null;
//        }
//        ToHeader toHeader = (ToHeader) serverTransaction.getRequest().getHeader(ToHeader.NAME);
//        if (toHeader.getTag() == null) {
//            toHeader.setTag(SipUtils.getNewTag());
//        }
//        SIPResponse response = (SIPResponse)getMessageFactory().createResponse(statusCode, serverTransaction.getRequest());
//        if (msg != null) {
//            response.setReasonPhrase(msg);
//        }
//        if (responseAckExtraParam != null) {
//            if (responseAckExtraParam.sipURI != null && serverTransaction.getRequest().getMethod().equals(Request.INVITE)) {
//                logger.debug("responseSdpAck SipURI: {}:{}", responseAckExtraParam.sipURI.getHost(), responseAckExtraParam.sipURI.getPort());
//                Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(
//                        SipFactory.getInstance().createAddressFactory().createSipURI(responseAckExtraParam.sipURI.getUser(),  responseAckExtraParam.sipURI.getHost()+":"+responseAckExtraParam.sipURI.getPort()
//                        ));
//                response.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
//            }
//            if (responseAckExtraParam.contentTypeHeader != null) {
//                response.setContent(responseAckExtraParam.content, responseAckExtraParam.contentTypeHeader);
//            }
//
//            if (serverTransaction.getRequest().getMethod().equals(Request.SUBSCRIBE)) {
//                if (responseAckExtraParam.expires == -1) {
//                    logger.error("[参数不全] 2xx的SUBSCRIBE回复,必须设置Expires header");
//                }else {
//                    ExpiresHeader expiresHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(responseAckExtraParam.expires);
//                    response.addHeader(expiresHeader);
//                }
//            }
//        }else {
//            if (serverTransaction.getRequest().getMethod().equals(Request.SUBSCRIBE)) {
//                logger.error("[参数不全] 2xx的SUBSCRIBE回复,必须设置Expires header");
//            }
//        }
//        serverTransaction.sendResponse(response);
//        if (statusCode >= 200 && !"NOTIFY".equalsIgnoreCase(serverTransaction.getRequest().getMethod())) {
//            if (serverTransaction.getDialog() != null) {
//                serverTransaction.getDialog().delete();
//            }
//        }
//        return response;
//    }
    public SIPResponse responseAck(SIPRequest sipRequest, int statusCode, String msg, ResponseAckExtraParam responseAckExtraParam) throws SipException, InvalidArgumentException, ParseException {
        if (sipRequest.getToHeader().getTag() == null) {
@@ -182,6 +138,8 @@
        return response;
    }
    /**
     * 回复带sdp的200
     */
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -152,10 +152,10 @@
            } else if (jsonObject.getInteger("code") == 0) {
                logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
            } else {
                logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSONObject.toJSON(param));
                logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSON.toJSON(param));
                if (sendRtpItem.isOnlyAudio()) {
                    // 语音对讲
                    Device device = deviceService.queryDevice(platformGbId);
                    Device device = deviceService.getDevice(platformGbId);
                    if (device != null) {
                        try {
                            cmder.streamByeCmd(device, sendRtpItem.getChannelId(), sendRtpItem.getStreamId(), null);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
@@ -111,7 +111,7 @@
            if (totalReaderCount <= 0) {
                logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId);
                if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) {
                    Device device = deviceService.queryDevice(sendRtpItem.getDeviceId());
                    Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
                    if (device == null) {
                        logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId);
                    }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -4,19 +4,14 @@
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.conf.exception.SsrcTransactionNotFoundException;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
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.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
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;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
@@ -25,11 +20,7 @@
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.*;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.service.IStreamProxyService;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.*;
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
@@ -37,8 +28,6 @@
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.AudioBroadcastResult;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import gov.nist.javax.sdp.TimeDescriptionImpl;
import gov.nist.javax.sdp.fields.TimeField;
import gov.nist.javax.sip.message.SIPRequest;
@@ -530,10 +519,9 @@
                            // 写入redis, 超时时回复
                            redisCatchStorage.updateSendRTPSever(sendRtpItem);
                            MediaServerItem finalMediaServerItem = mediaServerItem;
                            playService.play(mediaServerItem, ssrcInfo, device, channelId, hookEvent, errorEvent, (code, msg) -> {
                                logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId);
                                redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
                                logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, finalChannelId);
                                redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), finalChannelId, callIdHeader.getCallId(), null);
                            });
                        } else {
                            sendRtpItem.setStreamId(playTransaction.getStream());
@@ -908,13 +896,12 @@
        if (audioBroadcastCatch == null) {
            logger.warn("来自设备的Invite请求非语音广播,已忽略,requesterId: {}/{}", requesterId, channelId);
            try {
                responseAck(serverTransaction, Response.FORBIDDEN);
                responseAck(request, Response.FORBIDDEN);
            } catch (SipException | InvalidArgumentException | ParseException e) {
                logger.error("[命令发送失败] 来自设备的Invite请求非语音广播 FORBIDDEN: {}", e.getMessage());
            }
            return;
        }
        Request request = serverTransaction.getRequest();
        if (device != null) {
            logger.info("收到设备" + requesterId + "的语音广播Invite请求");
            try {
@@ -985,7 +972,7 @@
                if (mediaServerItem == null) {
                    logger.warn("未找到可用的zlm");
                    try {
                        responseAck(serverTransaction, Response.BUSY_HERE);
                        responseAck(request, Response.BUSY_HERE);
                    } catch (SipException | InvalidArgumentException | ParseException e) {
                        logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage());
                    }
@@ -997,7 +984,7 @@
                if (sendRtpItem == null) {
                    logger.warn("服务器端口资源不足");
                    try {
                        responseAck(serverTransaction, Response.BUSY_HERE);
                        responseAck(request, Response.BUSY_HERE);
                    } catch (SipException | InvalidArgumentException | ParseException e) {
                        logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
                    }
@@ -1024,7 +1011,7 @@
                Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream);
                if (streamReady) {
                    sendOk(device, sendRtpItem, sdp, serverTransaction, mediaServerItem, mediaTransmissionTCP, ssrc);
                    sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, ssrc);
                }else {
                    logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", app, stream);
                    playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
@@ -1042,7 +1029,7 @@
        }
    }
    void sendOk(Device device, SendRtpItem sendRtpItem, SessionDescription sdp, ServerTransaction serverTransaction,  MediaServerItem mediaServerItem, boolean mediaTransmissionTCP, String ssrc){
    void sendOk(Device device, SendRtpItem sendRtpItem, SessionDescription sdp, SIPRequest request,  MediaServerItem mediaServerItem, boolean mediaTransmissionTCP, String ssrc){
        try {
            sendRtpItem.setStatus(2);
            redisCatchStorage.updateSendRTPSever(sendRtpItem);
@@ -1078,7 +1065,7 @@
            parentPlatform.setServerPort(device.getPort());
            parentPlatform.setServerGBId(device.getDeviceId());
            SIPResponse sipResponse = responseSdpAck(serverTransaction, content.toString(), parentPlatform);
            SIPResponse sipResponse = responseSdpAck(request, content.toString(), parentPlatform);
            AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), sendRtpItem.getChannelId());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -101,33 +101,38 @@
        if (!taskQueueHandlerRun) {
            taskQueueHandlerRun = true;
            taskExecutor.execute(()-> {
                while (!taskQueue.isEmpty()) {
                    try {
                        HandlerCatchData take = taskQueue.poll();
                        Element rootElement = getRootElement(take.getEvt());
                        if (rootElement == null) {
                            logger.error("处理NOTIFY消息时未获取到消息体,{}", take.getEvt().getRequest());
                            continue;
                        }
                        String cmd = XmlUtil.getText(rootElement, "CmdType");
                try {
                    while (!taskQueue.isEmpty()) {
                        try {
                            HandlerCatchData take = taskQueue.poll();
                            Element rootElement = getRootElement(take.getEvt());
                            if (rootElement == null) {
                                logger.error("处理NOTIFY消息时未获取到消息体,{}", take.getEvt().getRequest());
                                continue;
                            }
                            String cmd = XmlUtil.getText(rootElement, "CmdType");
                        if (CmdType.CATALOG.equals(cmd)) {
                            logger.info("接收到Catalog通知");
                            processNotifyCatalogList(take.getEvt());
                        } else if (CmdType.ALARM.equals(cmd)) {
                            logger.info("接收到Alarm通知");
                            processNotifyAlarm(take.getEvt());
                        } else if (CmdType.MOBILE_POSITION.equals(cmd)) {
                            logger.info("接收到MobilePosition通知");
                            processNotifyMobilePosition(take.getEvt());
                        } else {
                            logger.info("接收到消息:" + cmd);
                            if (CmdType.CATALOG.equals(cmd)) {
                                logger.info("接收到Catalog通知");
                                processNotifyCatalogList(take.getEvt());
                            } else if (CmdType.ALARM.equals(cmd)) {
                                logger.info("接收到Alarm通知");
                                processNotifyAlarm(take.getEvt());
                            } else if (CmdType.MOBILE_POSITION.equals(cmd)) {
                                logger.info("接收到MobilePosition通知");
                                processNotifyMobilePosition(take.getEvt());
                            } else {
                                logger.info("接收到消息:" + cmd);
                            }
                        } catch (DocumentException e) {
                            logger.error("处理NOTIFY消息时错误", e);
                        }
                    } catch (DocumentException e) {
                        logger.error("处理NOTIFY消息时错误", e);
                    }
                }catch (Exception e) {
                    logger.error("处理NOTIFY消息时错误", e);
                }finally {
                    taskQueueHandlerRun = false;
                }
                taskQueueHandlerRun = false;
            });
        }
    }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -120,13 +120,6 @@
            if (request.getExpires() == null) {
                response = getMessageFactory().createResponse(Response.BAD_REQUEST, request);
                if (evt.getDialog() != null ) {
                    if (evt.getDialog().isServer()) {
                        ServerTransaction serverTransaction = getServerTransaction(evt);
                        serverTransaction.sendResponse(response);
                        serverTransaction.getDialog().delete();
                    }
                }
                sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
                return;
            }
@@ -183,14 +176,6 @@
            }
        } catch (SipException | NoSuchAlgorithmException | ParseException e) {
            e.printStackTrace();
        }
    }
    private void sendResponse(RequestEvent evt, Response response) throws InvalidArgumentException, SipException {
        ServerTransaction serverTransaction = getServerTransaction(evt);
        serverTransaction.sendResponse(response);
        if (serverTransaction.getDialog() != null) {
            serverTransaction.getDialog().delete();
        }
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java
@@ -3,15 +3,13 @@
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.AckRequestProcessor;
import gov.nist.javax.sip.message.SIPRequest;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
@@ -34,7 +32,11 @@
    public void handForDevice(RequestEvent evt, Device device, Element element) {
        String cmd = getText(element, "CmdType");
        if (cmd == null) {
            handNullCmd(evt);
            try {
                responseAck((SIPRequest) evt.getRequest(), Response.OK);
            } catch (SipException | InvalidArgumentException | ParseException e) {
                logger.error("[命令发送失败] 回复200 OK: {}", e.getMessage());
            }
            return;
        }
        IMessageHandler messageHandler = messageHandlerMap.get(cmd);
@@ -49,15 +51,6 @@
        IMessageHandler messageHandler = messageHandlerMap.get(cmd);
        if (messageHandler != null) {
            messageHandler.handForPlatform(evt, parentPlatform, element);
        }
    }
    public void handNullCmd(RequestEvent evt){
        try {
            ServerTransaction serverTransaction = getServerTransaction(evt);
            responseAck(serverTransaction, Response.OK);
        } catch (SipException | InvalidArgumentException | ParseException e) {
            logger.error("[命令发送失败] 回复200 OK: {}", e.getMessage());
        }
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
@@ -1,6 +1,6 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatchStatus;
import com.genersoft.iot.vmp.gb28181.bean.Device;
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
@@ -122,4 +122,21 @@
    public static String getNewCallId() {
        return (int) Math.floor(Math.random() * 10000) + "";
    }
    public static int getTypeCodeFromGbCode(String deviceId) {
        if (ObjectUtils.isEmpty(deviceId)) {
            return 0;
        }
        return Integer.parseInt(deviceId.substring(10, 13));
    }
    /**
     * 判断是否是前端外围设备
     * @param deviceId
     * @return
     */
    public static boolean isFrontEnd(String deviceId) {
        int typeCodeFromGbCode = getTypeCodeFromGbCode(deviceId);
        return typeCodeFromGbCode > 130 && typeCodeFromGbCode < 199;
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -9,21 +9,16 @@
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
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.dto.HookType;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.media.zlm.dto.*;
import com.genersoft.iot.vmp.service.*;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -294,9 +289,9 @@
        JSONObject json = (JSONObject) JSON.toJSON(param);
        taskExecutor.execute(()->{
        taskExecutor.execute(()-> {
            ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
            if (subscribe != null ) {
            if (subscribe != null) {
                MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
                if (mediaInfo != null) {
                    subscribe.response(mediaInfo, json);
@@ -312,15 +307,16 @@
                    StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
                    if (streamAuthorityInfo == null) {
                        streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
                    }else {
                    } else {
                        streamAuthorityInfo.setOriginType(param.getOriginType());
                        streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr());
                    }
                    redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
                }
            }else {
            } else {
                redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream());
            }
        });
        if ("rtsp".equals(param.getSchema())){
            logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", param.isRegist(), param.getApp(), param.getStream());
@@ -329,12 +325,12 @@
            }else {
                mediaServerService.removeCount(param.getMediaServerId());
            }
            if (item.getOriginType() == OriginType.PULL.ordinal()
                    || item.getOriginType() == OriginType.FFMPEG_PULL.ordinal()) {
            if (param.getOriginType() == OriginType.PULL.ordinal()
                    || param.getOriginType() == OriginType.FFMPEG_PULL.ordinal()) {
                // 设置拉流代理上线/离线
                streamProxyService.updateStatus(param.isRegist(), app, param.getStream());
                streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream());
            }
            if ("rtp".equals(app) && !regist ) {
            if ("rtp".equals(param.getApp()) && !param.isRegist() ) {
                StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(param.getStream());
                if (streamInfo!=null){
                    redisCatchStorage.stopPlay(streamInfo);
@@ -346,47 +342,49 @@
                                streamInfo.getStream(), null);
                    }
                }
            }else if ("broadcast".equals(app)){
            }else if ("broadcast".equals(param.getApp())){
                // 语音对讲推流  stream需要满足格式deviceId_channelId
                if (regist && param.getStream().indexOf("_") > 0) {
                if (param.isRegist() && param.getStream().indexOf("_") > 0) {
                    String[] streamArray = param.getStream().split("_");
                    if (streamArray.length == 2) {
                        String deviceId = streamArray[0];
                        String channelId = streamArray[1];
                        Device device = deviceService.queryDevice(deviceId);
                        Device device = deviceService.getDevice(deviceId);
                        if (device != null) {
                            DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
                            if (deviceChannel != null) {
                                if (audioBroadcastManager.exit(deviceId, channelId)) {
                                    // 直接推流
                                    SendRtpItem sendRtpItem =  redisCatchStorage.querySendRTPServer(null, null, stream, null);
                                    SendRtpItem sendRtpItem =  redisCatchStorage.querySendRTPServer(null, null, param.getStream(), null);
                                    if (sendRtpItem == null) {
                                        // TODO 可能数据错误,重新开启语音通道
                                    }else {
                                        String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
                                        MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
                                        logger.info("rtp/{}开始向上级推流, 目标={}:{},SSRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
                                        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");
                                        Map<String, Object> sendParam = new HashMap<>(12);
                                        sendParam.put("vhost","__defaultVhost__");
                                        sendParam.put("app",sendRtpItem.getApp());
                                        sendParam.put("stream",sendRtpItem.getStreamId());
                                        sendParam.put("ssrc", sendRtpItem.getSsrc());
                                        sendParam.put("src_port", sendRtpItem.getLocalPort());
                                        sendParam.put("pt", sendRtpItem.getPt());
                                        sendParam.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
                                        sendParam.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
                                        JSONObject jsonObject;
                                        if (sendRtpItem.isTcpActive()) {
                                            jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
                                            jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, sendParam);
                                        } else {
                                            param.put("is_udp", is_Udp);
                                            param.put("dst_url", sendRtpItem.getIp());
                                            param.put("dst_port", sendRtpItem.getPort());
                                            jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
                                            sendParam.put("is_udp", is_Udp);
                                            sendParam.put("dst_url", sendRtpItem.getIp());
                                            sendParam.put("dst_port", sendRtpItem.getPort());
                                            jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, sendParam);
                                        }
                                        if (jsonObject != null && jsonObject.getInteger("code") == 0) {
                                            logger.info("[语音对讲] 自动推流成功, device: {}, channel: {}", deviceId, channelId);
                                        }else {
                                            logger.info("[语音对讲] 推流失败, 结果: {}", jsonObject);
                                        }
                                    }
@@ -406,43 +404,43 @@
                    }
                }
            }else if ("talk".equals(app)){
            }else if ("talk".equals(param.getApp())){
                // 语音对讲推流  stream需要满足格式deviceId_channelId
                if (regist && stream.indexOf("_") > 0) {
                    String[] streamArray = stream.split("_");
                if (param.isRegist() && param.getStream().indexOf("_") > 0) {
                    String[] streamArray = param.getStream().split("_");
                    if (streamArray.length == 2) {
                        String deviceId = streamArray[0];
                        String channelId = streamArray[1];
                        Device device = deviceService.queryDevice(deviceId);
                        Device device = deviceService.getDevice(deviceId);
                        if (device != null) {
                            DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
                            if (deviceChannel != null) {
                                if (audioBroadcastManager.exit(deviceId, channelId)) {
                                    // 直接推流
                                    SendRtpItem sendRtpItem =  redisCatchStorage.querySendRTPServer(null, null, stream, null);
                                    SendRtpItem sendRtpItem =  redisCatchStorage.querySendRTPServer(null, null, param.getStream(), null);
                                    if (sendRtpItem == null) {
                                        // TODO 可能数据错误,重新开启语音通道
                                    }else {
                                        MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
                                        logger.info("rtp/{}开始向上级推流, 目标={}:{},SSRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
                                        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");
                                        Map<String, Object> sendParam = new HashMap<>(12);
                                        sendParam.put("vhost","__defaultVhost__");
                                        sendParam.put("app",sendRtpItem.getApp());
                                        sendParam.put("stream",sendRtpItem.getStreamId());
                                        sendParam.put("ssrc", sendRtpItem.getSsrc());
                                        sendParam.put("src_port", sendRtpItem.getLocalPort());
                                        sendParam.put("pt", sendRtpItem.getPt());
                                        sendParam.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
                                        sendParam.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
                                        JSONObject jsonObject;
                                        if (sendRtpItem.isTcpActive()) {
                                            jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
                                            jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, sendParam);
                                        } else {
                                            param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
                                            param.put("dst_url", sendRtpItem.getIp());
                                            param.put("dst_port", sendRtpItem.getPort());
                                            jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
                                            sendParam.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
                                            sendParam.put("dst_url", sendRtpItem.getIp());
                                            sendParam.put("dst_port", sendRtpItem.getPort());
                                            jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, sendParam);
                                        }
                                        if (jsonObject != null && jsonObject.getInteger("code") == 0) {
                                            logger.info("[语音对讲] 自动推流成功, device: {}, channel: {}", deviceId, channelId);
@@ -450,7 +448,7 @@
                                    }
                                }else {
                                    // 开启语音对讲通道
                                    MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
                                    MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
                                    playService.talk(mediaServerItem, device, channelId, (mediaServer, jsonObject)->{
                                        System.out.println("开始推流");
                                    }, eventResult -> {
@@ -466,9 +464,9 @@
                }
            }else{
                if (!"rtp".equals(app)){
                    String type = OriginType.values()[item.getOriginType()].getType();
                    MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
                if (!"rtp".equals(param.getApp())){
                    String type = OriginType.values()[param.getOriginType()].getType();
                    MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
                        if (mediaServerItem != null){
                            if (param.isRegist()) {
@@ -478,7 +476,7 @@
                                    callId = streamAuthorityInfo.getCallId();
                                }
                                StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem,
                                        param.getApp(), param.getStream(), tracks, callId);
                                        param.getApp(), param.getStream(), param.getTracks(), callId);
                                param.setStreamInfo(streamInfoByAppAndStream);
                                redisCatchStorage.addStream(mediaServerItem, type, param.getApp(), param.getStream(), param);
                                if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
@@ -489,7 +487,8 @@
                                }
                            }else {
                                // 兼容流注销时类型从redis记录获取
                                OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(param.getApp(), param.getStream(), param.getMediaServerId());
                                OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(
                                        param.getApp(), param.getStream(), param.getMediaServerId());
                                if (onStreamChangedHookParam != null) {
                                    type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType();
                                    redisCatchStorage.removeStream(mediaServerItem.getId(), type, param.getApp(), param.getStream());
@@ -526,13 +525,13 @@
                                if (platform != null) {
                                    commanderFroPlatform.streamByeCmd(platform, sendRtpItem);
                                }else {
                                    if ("talk".equals(app) && sendRtpItem.isOnlyAudio()) {
                                    if ("talk".equals(param.getApp()) && sendRtpItem.isOnlyAudio()) {
                                        AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
                                        if (device != null && audioBroadcastCatch != null) {
//                                            cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null);
                                        }
                                    }else {
                                        cmder.streamByeCmd(device, sendRtpItem.getChannelId(), stream, sendRtpItem.getCallId());
                                        cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId());
                                    }
                                }
@@ -575,6 +574,9 @@
                    if (sendRtpItems.size() > 0) {
                        for (SendRtpItem sendRtpItem : sendRtpItems) {
                            ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
                            if (parentPlatform == null) {
                                continue;
                            }
                            try {
                                commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
                            } catch (SipException | InvalidArgumentException | ParseException e) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -78,6 +78,7 @@
            if (callback == null) {
                try {
                    Response response = client.newCall(request).execute();
                    if (response.isSuccessful()) {
                        ResponseBody responseBody = response.body();
                        if (responseBody != null) {
@@ -85,6 +86,8 @@
                            responseJSON = JSON.parseObject(responseStr);
                        }
                    }else {
                        System.out.println( 2222);
                        System.out.println( response.code());
                        response.close();
                        Objects.requireNonNull(response.body()).close();
                    }
@@ -93,11 +96,11 @@
                    if(e instanceof SocketTimeoutException){
                        //读取超时超时异常
                        logger.error(String.format("读取ZLM数据失败: %s, %s", url, e.getMessage()));
                        logger.error(String.format("读取ZLM数据超时失败: %s, %s", url, e.getMessage()));
                    }
                    if(e instanceof ConnectException){
                        //判断连接异常,我这里是报Failed to connect to 10.7.5.144
                        logger.error(String.format("连接ZLM失败: %s, %s", url, e.getMessage()));
                        logger.error(String.format("连接ZLM连接失败: %s, %s", url, e.getMessage()));
                    }
                }catch (Exception e){
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -5,9 +5,9 @@
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
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.media.zlm.dto.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -346,23 +346,4 @@
        return result;
    }
    public void closeAllSendRtpStream() {
    }
    public MediaItem getMediaInfo(MediaServerItem mediaServerItem, String app, String stream) {
        JSONObject json = zlmresTfulUtils.getMediaList(mediaServerItem, app, stream);
        MediaItem mediaItem = null;
        if (json == null || json.getInteger("code") != 0) {
            return null;
        } else {
            JSONArray data = json.getJSONArray("data");
            if (data == null || data.size() == 0) {
                return null;
            }else {
                mediaItem = JSONObject.toJavaObject(data.getJSONObject(0), MediaItem.class);
            }
        }
        return mediaItem;
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java
@@ -37,7 +37,7 @@
    public static HookSubscribeForStreamPush on_publish(String app, String stream, String scheam, String mediaServerId) {
        HookSubscribeForStreamPush hookSubscribe = new HookSubscribeForStreamPush();
        JSONObject subscribeKey = new com.alibaba.fastjson.JSONObject();
        JSONObject subscribeKey = new JSONObject();
        subscribeKey.put("app", app);
        subscribeKey.put("stream", stream);
        if (scheam != null) {
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamPush.java
@@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.media.zlm.dto;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSONObject;
import java.time.Instant;
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItemLite.java
@@ -1,12 +1,6 @@
package com.genersoft.iot.vmp.media.zlm.dto;
import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import org.springframework.util.StringUtils;
import java.util.HashMap;
/**
 * 精简的MediaServerItem信息,方便给前端返回数据
 */
@@ -38,8 +32,6 @@
    private String secret;
    private int hookAliveInterval;
    private int recordAssistPort;
@@ -58,7 +50,6 @@
        this.rtspPort = mediaServerItem.getRtspPort();
        this.rtspSSLPort = mediaServerItem.getRtspSSLPort();
        this.secret = mediaServerItem.getSecret();
        this.hookAliveInterval = mediaServerItem.getHookAliveInterval();
        this.recordAssistPort = mediaServerItem.getRecordAssistPort();
    }
@@ -165,14 +156,6 @@
    public void setSecret(String secret) {
        this.secret = secret;
    }
    public int getHookAliveInterval() {
        return hookAliveInterval;
    }
    public void setHookAliveInterval(int hookAliveInterval) {
        this.hookAliveInterval = hookAliveInterval;
    }
    public int getRecordAssistPort() {
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -1,17 +1,12 @@
package com.genersoft.iot.vmp.service;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import java.util.List;
import java.util.Map;
/**
 * 媒体服务节点
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -4,20 +4,17 @@
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.common.StreamURL;
import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.service.IMediaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.net.URL;
@Service
public class MediaServiceImpl implements IMediaService {
@@ -104,7 +101,7 @@
        streamInfoResult.setFmp4(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam);
        streamInfoResult.setHls(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam);
        streamInfoResult.setTs(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam);
        streamInfoResult.setRtc(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam);
        streamInfoResult.setRtc(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app,  stream, callIdParam, isPlay);
        streamInfoResult.setTracks(tracks);
        return streamInfoResult;
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -1,62 +1,28 @@
package com.genersoft.iot.vmp.service.impl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.util.*;
import javax.sip.InvalidArgumentException;
import javax.sip.ResponseEvent;
import javax.sip.SipException;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
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.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.exception.ServiceException;
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.async.DeferredResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
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.bean.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
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.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
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.HookSubscribeForStreamChange;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -72,10 +38,10 @@
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -91,7 +57,9 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SuppressWarnings(value = {"rawtypes", "unchecked"})
@@ -1092,7 +1060,7 @@
        AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(deviceId, channelId);
        if (audioBroadcastCatch != null) {
            Device device = deviceService.queryDevice(deviceId);
            Device device = deviceService.getDevice(deviceId);
            if (device == null) {
                return;
            }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -111,22 +111,25 @@
            resultHolder.invokeResult(msg);
        });
        // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误
        deferredResultEx.setFilter(result1 -> {
            WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1;
            WVPResult<StreamInfo> clone = null;
            try {
                clone = (WVPResult<StreamInfo>)wvpResult1.clone();
            } catch (CloneNotSupportedException e) {
                throw new RuntimeException(e);
            }
            if (clone.getCode() == ErrorCode.SUCCESS.getCode()) {
                StreamInfo data = clone.getData().clone();
                data.channgeStreamIp(request.getLocalName());
                clone.setData(data);
            }
            return clone;
        });
        if (userSetting.isUsePushingAsStatus()) {
            // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误
            deferredResultEx.setFilter(result1 -> {
                WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1;
                WVPResult<StreamInfo> clone = null;
                try {
                    clone = (WVPResult<StreamInfo>)wvpResult1.clone();
                } catch (CloneNotSupportedException e) {
                    throw new RuntimeException(e);
                }
                if (clone.getCode() == ErrorCode.SUCCESS.getCode()) {
                    StreamInfo data = clone.getData().clone();
                    data.channgeStreamIp(request.getLocalName());
                    clone.setData(data);
                }
                return clone;
            });
        }
        // 录像查询以channelId作为deviceId查询
        resultHolder.put(key, uuid, deferredResultEx);
web_src/src/components/dialog/devicePlayer.vue
@@ -302,15 +302,13 @@
<script>
import rtcPlayer from '../dialog/rtcPlayer.vue'
import crypto from 'crypto'
// import LivePlayer from '@liveqing/liveplayer'
// import player from '../dialog/easyPlayer.vue'
import jessibucaPlayer from '../common/jessibuca.vue'
import recordDownload from '../dialog/recordDownload.vue'
export default {
    name: 'devicePlayer',
    props: {},
    components: {
      LivePlayer, jessibucaPlayer, rtcPlayer, recordDownload,
      jessibucaPlayer, rtcPlayer, recordDownload,
    },
    computed: {
        getPlayerShared: function () {
@@ -864,9 +862,9 @@
                if (res.data.code == 0) {
                  let streamInfo = res.data.data.streamInfo;
                  if (document.location.protocol.includes("https")) {
                    this.startBroadcast(streamInfo.rtcs)
                    this.startBroadcast(streamInfo.rtcs.url)
                  }else {
                    this.startBroadcast(streamInfo.rtc)
                    this.startBroadcast(streamInfo.rtc.url)
                  }
                }else {