فهرست منبع

暂存,待修改为回复带sdp的200
1. 配置文件修改,编译脚本修改

kindring 2 سال پیش
والد
کامیت
9f242b6310

+ 28 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/GBEventSubscribe.java

@@ -8,6 +8,7 @@ import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
+import javax.sip.ServerTransaction;
 import java.time.Instant;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
@@ -33,6 +34,33 @@ public class GBEventSubscribe {
         allSubscribes.computeIfAbsent(hookSubscribe.getHookType(), k -> new ConcurrentHashMap<>()).put(hookSubscribe, event);
     }
 
+    public GBEventSubscribe.Event sendStreamNotify(String type, JSONObject hookResponse, ServerTransaction serverTransaction){
+        GBEventSubscribe.Event event = null;
+        Map<IGBHookSubscribe, GBEventSubscribe.Event> eventMap = allSubscribes.get(type);
+        if (eventMap == null) {
+            logger.warn("[发送国标通知失败] {}",type);
+            return null;
+        }
+        logger.info("[触发国标推送] {}",type);
+        for (IGBHookSubscribe key : eventMap.keySet()) {
+            Boolean result = null;
+            logger.info("[触发国标推送] key:{}",key.getContent());
+            for (String s : key.getContent().keySet()) {
+                if (result == null) {
+                    result = key.getContent().getString(s).equals(hookResponse.getString(s));
+                }else {
+                    if (key.getContent().getString(s) == null) {
+                        continue;
+                    }
+                    result = result && key.getContent().getString(s).equals(hookResponse.getString(s));
+                }
+            }
+            if (null != result && result) {
+                event = eventMap.get(key);
+            }
+        }
+        return event;
+    }
     public GBEventSubscribe.Event sendNotify(String type, JSONObject hookResponse) {
         GBEventSubscribe.Event event = null;
         Map<IGBHookSubscribe, GBEventSubscribe.Event> eventMap = allSubscribes.get(type);

+ 37 - 18
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@@ -511,7 +511,7 @@ public class SIPCommander implements ISIPCommander {
     }
 
 
-    public void sendBoradcastInviteCmd(MediaServerItem mediaServerItem,SSRCInfo ssrcInfo,Device device,
+    public void sendBoradcastInviteCmd(ServerTransaction serverTransaction,MediaServerItem mediaServerItem,SSRCInfo ssrcInfo,Device device,
                                        String startTime, String endTime,
                                        InviteStreamCallback inviteStreamCallback,
                                        SipSubscribe.Event okEvent,
@@ -519,28 +519,47 @@ public class SIPCommander implements ISIPCommander {
             InvalidArgumentException, SipException, ParseException{
         logger.info("{} 语音对讲拉语音流的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
         int testPort = 31234;
+        // 创建sdp
         StringBuffer content = new StringBuffer(200);
         content.append("v=0\r\n");
-        content.append("o=" + device.getDeviceId() + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
+        content.append("o=" + sipConfig.getId() + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
         content.append("s=Play\r\n");
-        content.append("u=" + device.getDeviceId() + ":0\r\n");
         content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
-//        content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "
-//                + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");
-
-        // 使用send only 发送audio拉流地址
+        content.append("t=" + 0 + " "+ 0 + "\r\n");
         content.append("m=audio " + ssrcInfo.getPort() + " TCP/RTP/AVP 8\r\n");
-
-//        content.append("m=audio " + testPort + " TCP/RTP/AVP 8 16 24\r\n");
         content.append("a=sendonly\r\n");
         content.append("a=rtpmap:8 PCMA/8000\r\n");
-//        content.append("a=rtpmap:16 PCMU/8000\r\n");
-//        content.append("a=rtpmap:24 OPUS/8000\r\n");
         content.append("a=setup:passive\r\n");
         content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
-        content.append("y=v/////a/1/8/1\r\n");//ssrc
-        CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
-                : udpSipProvider.getNewCallId();
+        content.append("f=v/////a/1/8/1\r\n");//f 参数?
+        String _ssrc = ssrcInfo.getSsrc();
+        // 使用 返回sdp ack 数据给设备
+        try {
+            CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
+                    : udpSipProvider.getNewCallId();
+            dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
+                logger.info("Ack 等待超时");
+                // 释放 zlm 的推流端口
+                mediaServerService.releaseSsrc(mediaServerItem.getId(), _ssrc );
+                // todo 等待 broadcast invite的 200 sdp 超时  回复bye
+//                try {
+//                    cmderFroPlatform.streamByeCmd(platform, callIdHeader.getCallId());
+//                } catch (SipException | InvalidArgumentException | ParseException e) {
+//                    logger.error("[命令发送失败] 语音广播 发送BYE: {}", e.getMessage());
+//                }
+            }, 60 * 1000);
+            responseSdpACK(serverTransaction,
+                    content.toString(),
+                    device.getDeviceId(),
+                    device.getHostAddress(),
+                    device.getPort()
+            );
+        }catch(SipException e){
+            logger.warn("下发audio invite 失败");
+        }
+
+
+
         logger.info("下发audio invite 为{}",content.toString());
         // todo 订阅audio推流流变化
         Request request = headerProvider.createPlaybackInviteRequest(device,null, content.toString(), null, SipUtils.getNewFromTag(), null, callIdHeader, ssrcInfo.getSsrc());
@@ -552,9 +571,9 @@ public class SIPCommander implements ISIPCommander {
             streamSession.put(device.getDeviceId(), null, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.playback);
             okEvent.response(event);
         });
-        if (inviteStreamCallback != null) {
-            inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
-        }
+//        if (inviteStreamCallback != null) {
+//            inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
+//        }
     }
     /**
      * 请求历史媒体下载
@@ -718,7 +737,7 @@ public class SIPCommander implements ISIPCommander {
         broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
 
 //        broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
-        broadcastXml.append("<SourceID>" + webrtcStreamId + "</SourceID>\r\n");
+        broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
 
         broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
         broadcastXml.append("</Notify>\r\n");

+ 18 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java

@@ -211,6 +211,24 @@ public abstract class SIPRequestProcessorParent {
 		return responseAck(serverTransaction, Response.OK, null, responseAckExtraParam);
 	}
 
+	public SIPResponse responseSdpACK(ServerTransaction serverTransaction, String sdp,String gbId,String addr,int port) throws SipException, InvalidArgumentException, ParseException {
+		logger.info("response sdp Ack by broadcast");
+		ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
+
+		// 兼容国标中的使用编码@域名作为RequestURI的情况
+		SipURI sipURI = (SipURI)serverTransaction.getRequest().getRequestURI();
+		if (sipURI.getPort() == -1) {
+			// 此段为回复id
+			sipURI = SipFactory.getInstance().createAddressFactory().createSipURI(gbId,  addr+":"+port);
+		}
+		ResponseAckExtraParam responseAckExtraParam = new ResponseAckExtraParam();
+		responseAckExtraParam.contentTypeHeader = contentTypeHeader;
+		responseAckExtraParam.content = sdp;
+		responseAckExtraParam.sipURI = sipURI;
+
+		return responseAck(serverTransaction, Response.OK, null, responseAckExtraParam);
+	}
+
 	/**
 	 * 回复带xml的200
 	 */