From 4b827f3897600e97023ded3df83a2f2551131d53 Mon Sep 17 00:00:00 2001
From: 648540858 <648540858@qq.com>
Date: 星期二, 13 十二月 2022 11:57:07 +0800
Subject: [PATCH] 级联语音对讲部分
---
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java | 6
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java | 48 ++
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java | 20
src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java | 4
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java | 88 ++++
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java | 22
src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java | 28 +
web_src/src/components/dialog/devicePlayer.vue | 8
doc/_sidebar.md | 1
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java | 10
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java | 79 +++
doc/README.md | 4
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java | 2
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java | 9
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java | 155 +++++++
doc/_content/theory/broadcast_cascade.md | 46 ++
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java | 6
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java | 6
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java | 50 +-
src/main/resources/all-application.yml | 4
src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java | 83 ++++
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java | 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java | 59 --
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java | 7
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java | 91 +---
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java | 123 ++++++
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java | 200 ++++++++++
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java | 2
28 files changed, 940 insertions(+), 223 deletions(-)
diff --git a/doc/README.md b/doc/README.md
index 0fb5b86..2bbc184 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -52,7 +52,7 @@
- [X] 鎶ヨ璁㈤槄
- [X] 鐩綍璁㈤槄
- [ ] 璇煶骞挎挱
-- [ ] 璇煶瀵硅
+- [ ] 璇煶鍠婅瘽
**浣滀负涓嬬骇骞冲彴**
- [X] 娉ㄥ唽
@@ -91,7 +91,7 @@
- [ ] 鎶ヨ璁㈤槄
- [X] 鐩綍璁㈤槄
- [ ] 璇煶骞挎挱
-- [ ] 璇煶瀵硅
+- [ ] 璇煶鍠婅瘽
diff --git a/doc/_content/theory/broadcast_cascade.md b/doc/_content/theory/broadcast_cascade.md
new file mode 100644
index 0000000..e59b8c2
--- /dev/null
+++ b/doc/_content/theory/broadcast_cascade.md
@@ -0,0 +1,46 @@
+<!-- 鐐规挱娴佺▼ -->
+
+# 鐐规挱娴佺▼
+> 浠ヤ笅涓篧VP-PRO绾ц仈璇煶鍠婅瘽娴佺▼銆�
+
+```plantuml
+@startuml
+"涓婄骇骞冲彴" -> "涓嬬骇骞冲彴": 1. 鍙戣捣璇煶鍠婅瘽璇锋眰
+"涓婄骇骞冲彴" <-- "涓嬬骇骞冲彴": 2. 200OK
+"涓婄骇骞冲彴" <- "涓嬬骇骞冲彴": 3. 鍥炲Result OK
+"涓婄骇骞冲彴" --> "涓嬬骇骞冲彴": 4. 200OK
+
+"涓嬬骇骞冲彴" -> "璁惧": 5. 鍙戣捣璇煶鍠婅瘽璇锋眰
+"涓嬬骇骞冲彴" <-- "璁惧": 6. 200OK
+"涓嬬骇骞冲彴" <- "璁惧": 7. 鍥炲Result OK
+"涓嬬骇骞冲彴" --> "璁惧": 8. 200OK
+
+"涓嬬骇骞冲彴" <- "璁惧": 9. invite(broadcast)
+"涓嬬骇骞冲彴" --> "璁惧": 10. 100 trying
+"涓嬬骇骞冲彴" --> "璁惧": 11. 200OK SDP
+"涓嬬骇骞冲彴" <-- "璁惧": 12. ack
+
+"涓婄骇骞冲彴" <- "涓嬬骇骞冲彴": 13. invite(broadcast)
+"涓婄骇骞冲彴" --> "涓嬬骇骞冲彴": 14. 100 trying
+"涓婄骇骞冲彴" --> "涓嬬骇骞冲彴": 15. 200OK SDP
+"涓婄骇骞冲彴" <-- "涓嬬骇骞冲彴": 16. ack
+
+"涓婄骇骞冲彴" -> "涓嬬骇骞冲彴": 17. 鎺ㄩ�丷TP
+"涓嬬骇骞冲彴" -> "璁惧": 18. 鎺ㄩ�丷TP
+
+@enduml
+```
+
+
+## 娉ㄥ唽娴佺▼鎻忚堪濡備笅:
+1. 鐢ㄦ埛浠庣綉椤垫垨璋冪敤鎺ュ彛鍙戣捣鐐规挱璇锋眰;
+2. WVP-PRO鍚戞憚鍍忔満鍙戦�両nvite娑堟伅,娑堟伅澶村煙涓惡甯� Subject瀛楁,琛ㄦ槑鐐规挱鐨勮棰戞簮ID銆佸彂閫佹柟濯掍綋娴佸簭鍒楀彿銆乑LMediaKit鎺ユ敹娴佷娇鐢ㄧ殑IP銆佺鍙e彿銆�
+ 鎺ユ敹绔獟浣撴祦搴忓垪鍙风瓑鍙傛暟,SDP娑堟伅浣撲腑 s瀛楁涓衡�淧lay鈥濅唬琛ㄥ疄鏃剁偣鎾紝y瀛楁鎻忚堪SSRC鍊�,f瀛楁鎻忚堪濯掍綋鍙傛暟銆�
+3. 鎽勫儚鏈哄悜WVP-PRO鍥炲200OK锛屾秷鎭綋涓弿杩颁簡濯掍綋娴佸彂閫佽�呭彂閫佸獟浣撴祦鐨処P銆佺鍙c�佸獟浣撴牸寮忋�丼SRC瀛楁绛夊唴瀹广��
+4. WVP-PRO鍚戣澶囧洖澶岮ck锛� 浼氳瘽寤虹珛鎴愬姛銆�
+5. 璁惧鍚慫LMediaKit鍙戦�佸疄鏃舵祦銆�
+6. ZLMediaKit鍚慦VP-PRO鍙戦�佹祦鏀瑰彉浜嬩欢銆�
+7. WVP-PRO鍚慦EB鐢ㄦ埛鍥炲鎾斁鍦板潃銆�
+8. ZLMediaKit鍚慦VP鍙戦�佹祦鏃犱汉瑙傜湅浜嬩欢銆�
+9. WVP-PRO鍚戣澶囧洖澶岯ye锛� 缁撴潫浼氳瘽銆�
+10. 璁惧鍥炲200OK锛屼細璇濈粨鏉熸垚鍔熴��
diff --git a/doc/_sidebar.md b/doc/_sidebar.md
index 3b10bae..05101c1 100644
--- a/doc/_sidebar.md
+++ b/doc/_sidebar.md
@@ -19,6 +19,7 @@
* [鏍戝舰缁撴瀯](_content/theory/channel_tree.md)
* [娉ㄥ唽娴佺▼](_content/theory/register.md)
* [鐐规挱娴佺▼](_content/theory/play.md)
+ * [绾ц仈璇煶鍠婅瘽娴佺▼](_content/theory/broadcast_cascade.md)
* **蹇呭鎶�宸�**
* [鎶撳寘](_content/skill/tcpdump.md)
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
index a2d3054..581ea6f 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -47,6 +47,8 @@
private String thirdPartyGBIdReg = "[\\s\\S]*";
+ private String broadcastForPlatform = "UDP";
+
private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
public Boolean getSavePositionHistory() {
@@ -196,4 +198,12 @@
public void setSyncChannelOnDeviceOnline(Boolean syncChannelOnDeviceOnline) {
this.syncChannelOnDeviceOnline = syncChannelOnDeviceOnline;
}
+
+ public String getBroadcastForPlatform() {
+ return broadcastForPlatform;
+ }
+
+ public void setBroadcastForPlatform(String broadcastForPlatform) {
+ this.broadcastForPlatform = broadcastForPlatform;
+ }
}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
index 88db807..d9e89fa 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
@@ -1,6 +1,8 @@
package com.genersoft.iot.vmp.gb28181.bean;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
import gov.nist.javax.sip.message.SIPResponse;
/**
@@ -10,10 +12,24 @@
public class AudioBroadcastCatch {
- public AudioBroadcastCatch(String deviceId, String channelId, AudioBroadcastCatchStatus status) {
+ public AudioBroadcastCatch(
+ String deviceId,
+ String channelId,
+ MediaServerItem mediaServerItem,
+ String app,
+ String stream,
+ AudioBroadcastEvent event,
+ AudioBroadcastCatchStatus status,
+ boolean isFromPlatform
+ ) {
this.deviceId = deviceId;
this.channelId = channelId;
this.status = status;
+ this.event = event;
+ this.isFromPlatform = isFromPlatform;
+ this.app = app;
+ this.stream = stream;
+ this.mediaServerItem = mediaServerItem;
}
public AudioBroadcastCatch() {
@@ -30,6 +46,26 @@
private String channelId;
/**
+ * 娴佸獟浣撲俊鎭�
+ */
+ private MediaServerItem mediaServerItem;
+
+ /**
+ * 鍏宠仈鐨勬祦APP
+ */
+ private String app;
+
+ /**
+ * 鍏宠仈鐨勬祦STREAM
+ */
+ private String stream;
+
+ /**
+ * 鏄惁鏄骇鑱旇闊冲枈璇�
+ */
+ private boolean isFromPlatform;
+
+ /**
* 璇煶骞挎挱鐘舵��
*/
private AudioBroadcastCatchStatus status;
@@ -38,6 +74,11 @@
* 璇锋眰淇℃伅
*/
private SipTransactionInfo sipTransactionInfo;
+
+ /**
+ * 璇锋眰缁撴灉鍥炶皟
+ */
+ private AudioBroadcastEvent event;
public String getDeviceId() {
@@ -75,4 +116,44 @@
public void setSipTransactionInfoByRequset(SIPResponse response) {
this.sipTransactionInfo = new SipTransactionInfo(response, false);
}
+
+ public AudioBroadcastEvent getEvent() {
+ return event;
+ }
+
+ public void setEvent(AudioBroadcastEvent event) {
+ this.event = event;
+ }
+
+ public String getApp() {
+ return app;
+ }
+
+ public void setApp(String app) {
+ this.app = app;
+ }
+
+ public String getStream() {
+ return stream;
+ }
+
+ public void setStream(String stream) {
+ this.stream = stream;
+ }
+
+ public boolean isFromPlatform() {
+ return isFromPlatform;
+ }
+
+ public void setFromPlatform(boolean fromPlatform) {
+ isFromPlatform = fromPlatform;
+ }
+
+ public MediaServerItem getMediaServerItem() {
+ return mediaServerItem;
+ }
+
+ public void setMediaServerItem(MediaServerItem mediaServerItem) {
+ this.mediaServerItem = mediaServerItem;
+ }
}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java
index a3098fb..dde7639 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java
@@ -2,7 +2,7 @@
public enum InviteStreamType {
- PLAY,PLAYBACK,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY,TALK
+ PLAY,PLAYBACK,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY,BROADCAST,TALK
}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
index b056cc7..262ac55 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
@@ -66,7 +66,7 @@
* 璁惧绔彛
*/
@Schema(description = "璁惧绔彛")
- private String devicePort;
+ private int devicePort;
/**
* SIP璁よ瘉鐢ㄦ埛鍚�(榛樿浣跨敤璁惧鍥芥爣缂栧彿)
@@ -261,11 +261,11 @@
this.deviceIp = deviceIp;
}
- public String getDevicePort() {
+ public int getDevicePort() {
return devicePort;
}
- public void setDevicePort(String devicePort) {
+ public void setDevicePort(int devicePort) {
this.devicePort = devicePort;
}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
index e7409bf..5cc9cb9 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
@@ -1,6 +1,5 @@
package com.genersoft.iot.vmp.gb28181.event;
-import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent;
import gov.nist.javax.sip.message.SIPRequest;
import org.slf4j.Logger;
@@ -87,6 +86,11 @@
public String callId;
public EventObject event;
+ public EventResult(int statusCode, String msg) {
+ this.statusCode = statusCode;
+ this.msg = msg;
+ }
+
public EventResult(EventObject event) {
this.event = event;
if (event instanceof ResponseEvent) {
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java
index 7186fad..072d0cb 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java
@@ -23,10 +23,6 @@
public static Map<String, AudioBroadcastCatch> data = new ConcurrentHashMap<>();
- public void add(AudioBroadcastCatch audioBroadcastCatch) {
- this.update(audioBroadcastCatch);
- }
-
public void update(AudioBroadcastCatch audioBroadcastCatch) {
if (SipUtils.isFrontEnd(audioBroadcastCatch.getDeviceId())) {
data.put(audioBroadcastCatch.getDeviceId(), audioBroadcastCatch);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
index a351445..43d4186 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
@@ -49,8 +49,6 @@
public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM";
- public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST";
-
private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>();
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
index 13a36d7..f0d453b 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
@@ -1,8 +1,12 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd;
+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.media.zlm.ZlmHttpHookSubscribe;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
+import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
@@ -14,77 +18,98 @@
/**
* 鍚戜笂绾у钩鍙版敞鍐�
+ *
* @param parentPlatform
* @return
*/
- void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
- void register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException;
+ void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent)
+ throws InvalidArgumentException, ParseException, SipException;
+
+ void register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www,
+ SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister)
+ throws SipException, InvalidArgumentException, ParseException;
/**
* 鍚戜笂绾у钩鍙版敞閿�
+ *
* @param parentPlatform
* @return
*/
- void unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
+ void unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent)
+ throws InvalidArgumentException, ParseException, SipException;
/**
* 鍚戜笂绾у钩鍙戦�佸績璺充俊鎭�
+ *
* @param parentPlatform
* @return callId(浣滀负鎺ュ彈鍥炲鐨勫垽瀹�)
*/
- String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException;
+ String keepalive(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent)
+ throws SipException, InvalidArgumentException, ParseException;
/**
* 鍚戜笂绾у洖澶嶉�氶亾淇℃伅
- * @param channel 閫氶亾淇℃伅
+ *
+ * @param channel 閫氶亾淇℃伅
* @param parentPlatform 骞冲彴淇℃伅
* @param sn
* @param fromTag
* @param size
* @return
*/
- void catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size) throws SipException, InvalidArgumentException, ParseException;
- void catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag) throws InvalidArgumentException, ParseException, SipException;
+ void catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size)
+ throws SipException, InvalidArgumentException, ParseException;
+
+ void catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag)
+ throws InvalidArgumentException, ParseException, SipException;
/**
* 鍚戜笂绾у洖澶岲eviceInfo鏌ヨ淇℃伅
+ *
* @param parentPlatform 骞冲彴淇℃伅
* @param sn
* @param fromTag
* @return
*/
- void deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException;
+ void deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag)
+ throws SipException, InvalidArgumentException, ParseException;
/**
* 鍚戜笂绾у洖澶岲eviceStatus鏌ヨ淇℃伅
+ *
* @param parentPlatform 骞冲彴淇℃伅
* @param sn
* @param fromTag
* @return
*/
- void deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException;
+ void deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag)
+ throws SipException, InvalidArgumentException, ParseException;
/**
* 鍚戜笂绾у洖澶嶇Щ鍔ㄤ綅缃闃呮秷鎭�
+ *
* @param parentPlatform 骞冲彴淇℃伅
- * @param gpsMsgInfo GPS淇℃伅
- * @param subscribeInfo 璁㈤槄鐩稿叧鐨勪俊鎭�
+ * @param gpsMsgInfo GPS淇℃伅
+ * @param subscribeInfo 璁㈤槄鐩稿叧鐨勪俊鎭�
* @return
*/
- void sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException;
+ void sendNotifyMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo)
+ throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException;
/**
* 鍚戜笂绾у洖澶嶆姤璀︽秷鎭�
+ *
* @param parentPlatform 骞冲彴淇℃伅
- * @param deviceAlarm 鎶ヨ淇℃伅淇℃伅
+ * @param deviceAlarm 鎶ヨ淇℃伅淇℃伅
* @return
*/
void sendAlarmMessage(ParentPlatform parentPlatform, DeviceAlarm deviceAlarm) throws SipException, InvalidArgumentException, ParseException;
/**
* 鍥炲catalog浜嬩欢-澧炲姞/鏇存柊
+ *
* @param parentPlatform
* @param deviceChannels
*/
@@ -92,22 +117,28 @@
/**
* 鍥炲catalog浜嬩欢-鍒犻櫎
+ *
* @param parentPlatform
* @param deviceChannels
*/
- void sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException;
+ void sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels,
+ SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException,
+ ParseException, NoSuchFieldException, SipException, IllegalAccessException;
/**
* 鍥炲recordInfo
- * @param deviceChannel 閫氶亾淇℃伅
+ *
+ * @param deviceChannel 閫氶亾淇℃伅
* @param parentPlatform 骞冲彴淇℃伅
- * @param fromTag fromTag
- * @param recordInfo 褰曞儚淇℃伅
+ * @param fromTag fromTag
+ * @param recordInfo 褰曞儚淇℃伅
*/
- void recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo) throws SipException, InvalidArgumentException, ParseException;
+ void recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo)
+ throws SipException, InvalidArgumentException, ParseException;
/**
* 褰曞儚鎾斁鎺ㄩ�佸畬鎴愭椂鍙戦�丮ediaStatus娑堟伅
+ *
* @param platform
* @param sendRtpItem
* @return
@@ -116,9 +147,19 @@
/**
* 鍚戝彂璧风偣鎾殑涓婄骇鍥炲bye
+ *
* @param platform 骞冲彴淇℃伅
- * @param callId callId
+ * @param callId callId
*/
void streamByeCmd(ParentPlatform platform, String callId) throws SipException, InvalidArgumentException, ParseException;
+
void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException;
+
+ void streamByeCmd(ParentPlatform platform, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
+
+ void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem,
+ SSRCInfo ssrcInfo, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent,
+ SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException;
+
+ void broadcastResultCmd(ParentPlatform platform, DeviceChannel deviceChannel, String sn, boolean result, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
index 0fe11c0..e80f427 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
@@ -4,6 +4,7 @@
import com.genersoft.iot.vmp.gb28181.SipLayer;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
+import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -14,7 +15,8 @@
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
-import javax.sip.*;
+import javax.sip.InvalidArgumentException;
+import javax.sip.PeerUnavailableException;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
@@ -22,7 +24,6 @@
import javax.validation.constraints.NotNull;
import java.text.ParseException;
import java.util.ArrayList;
-import java.util.List;
import java.util.UUID;
/**
@@ -175,7 +176,7 @@
SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), serverAddress);
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
- ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), Integer.parseInt(parentPlatform.getDevicePort()),
+ ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), parentPlatform.getDevicePort(),
parentPlatform.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
@@ -212,7 +213,7 @@
SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP()+ ":" + parentPlatform.getServerPort());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<>();
- ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), Integer.parseInt(parentPlatform.getDevicePort()),
+ ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), parentPlatform.getDevicePort(),
parentPlatform.getTransport(), SipUtils.getNewViaTag());
viaHeader.setRPort();
viaHeaders.add(viaHeader);
@@ -272,7 +273,7 @@
SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(platform.getServerGBId(), platform.getServerIP()+ ":" + platform.getServerPort());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<>();
- ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(platform.getDeviceIp(), Integer.parseInt(platform.getDevicePort()),
+ ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(platform.getDeviceIp(), platform.getDevicePort(),
platform.getTransport(), SipUtils.getNewViaTag());
viaHeader.setRPort();
viaHeaders.add(viaHeader);
@@ -308,4 +309,81 @@
return request;
}
+
+ public Request createInviteRequest(ParentPlatform platform, String channelId, String toString, String viaTag, String fromTag, Object content, String ssrc, CallIdHeader callIdHeader, String transport) throws PeerUnavailableException, ParseException, InvalidArgumentException {
+ Request request = null;
+ //璇锋眰琛�
+ String deviceHostAddress = platform.getDeviceIp() + ":" + platform.getDevicePort();
+ SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, deviceHostAddress);
+ //via
+ ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
+ HeaderFactory headerFactory = sipLayer.getSipFactory().createHeaderFactory();
+ ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getDevicePort(), platform.getTransport(), viaTag);
+ viaHeader.setRPort();
+ viaHeaders.add(viaHeader);
+
+ //from
+ 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); //蹇呴』瑕佹湁鏍囪锛屽惁鍒欐棤娉曞垱寤轰細璇濓紝鏃犳硶鍥炲簲ack
+ //to
+ SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, deviceHostAddress);
+ Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);
+ ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,null);
+
+ //Forwards
+ MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70);
+
+ //ceq
+ CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);
+ request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
+
+ request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil));
+
+ Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(platform.getDeviceIp())+":"+ deviceHostAddress));
+ // Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
+ request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress));
+ // Subject
+ SubjectHeader subjectHeader = sipLayer.getSipFactory().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
+ request.addHeader(subjectHeader);
+ ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
+ request.setContent(content, contentTypeHeader);
+ return request;
+ }
+
+ public Request createByteRequest(ParentPlatform platform, String channelId, SipTransactionInfo transactionInfo) throws PeerUnavailableException, ParseException, InvalidArgumentException {
+ String deviceHostAddress = platform.getDeviceIp() + ":" + platform.getDevicePort();
+ Request request = null;
+ SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, deviceHostAddress);
+
+ // via
+ ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
+ ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getDevicePort(), platform.getTransport(), SipUtils.getNewViaTag());
+ viaHeaders.add(viaHeader);
+ //from
+ SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
+ Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);
+ FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.isFromServer()?transactionInfo.getFromTag():transactionInfo.getToTag());
+ //to
+ SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, deviceHostAddress);
+ Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);
+ ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,transactionInfo.isFromServer()?transactionInfo.getToTag():transactionInfo.getFromTag());
+
+ //Forwards
+ MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70);
+
+ //ceq
+ CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);
+ CallIdHeader callIdHeader = sipLayer.getSipFactory().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
+ request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
+
+ request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil));
+
+ Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(platform.getDeviceIp())+":"+ platform.getDevicePort()));
+ request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress));
+
+ request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil));
+
+ return request;
+ }
}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
index 29f2bec..425dd93 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -590,12 +590,12 @@
return;
}
if (!mediaServerItem.isRtpEnable()) {
- // 鍗曠鍙f殏涓嶆敮鎸佽闊冲璁�
- logger.info("[璇煶瀵硅] 鍗曠鍙f殏涓嶆敮鎸佹鎿嶄綔");
+ // 鍗曠鍙f殏涓嶆敮鎸佽闊冲枈璇�
+ logger.info("[璇煶鍠婅瘽] 鍗曠鍙f殏涓嶆敮鎸佹鎿嶄綔");
return;
}
- logger.info("[璇煶瀵硅] {} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
+ logger.info("[璇煶鍠婅瘽] {} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
subscribe.addSubscribe(hookSubscribeForStreamChange, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
if (event != null) {
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
index 08cc3c3..d0d72bf 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -1,22 +1,31 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.conf.UserSetting;
+import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
import com.genersoft.iot.vmp.gb28181.SipLayer;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
+import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
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.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;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
+import com.genersoft.iot.vmp.service.bean.SSRCInfo;
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 gov.nist.javax.sip.message.SIPResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -26,6 +35,7 @@
import org.springframework.util.ObjectUtils;
import javax.sip.InvalidArgumentException;
+import javax.sip.ResponseEvent;
import javax.sip.SipException;
import javax.sip.header.CallIdHeader;
import javax.sip.header.WWWAuthenticateHeader;
@@ -60,6 +70,16 @@
@Autowired
private SIPSender sipSender;
+
+ @Autowired
+ private ZlmHttpHookSubscribe subscribe;
+
+ @Autowired
+ private UserSetting userSetting;
+
+
+ @Autowired
+ private VideoStreamSessionManager streamSession;
@Override
public void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {
@@ -645,4 +665,107 @@
}
sipSender.transmitRequest(platform.getDeviceIp(),byeRequest);
}
+
+ @Override
+ public void streamByeCmd(ParentPlatform platform, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
+ SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(platform.getServerGBId(), channelId, callId, stream);
+ if (ssrcTransaction == null) {
+ throw new SsrcTransactionNotFoundException(platform.getServerGBId(), channelId, callId, stream);
+ }
+
+ mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());
+ mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream());
+ streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
+
+ Request byteRequest = headerProviderPlatformProvider.createByteRequest(platform, channelId, ssrcTransaction.getSipTransactionInfo());
+ sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), byteRequest, null, okEvent);
+ }
+
+ @Override
+ public void broadcastResultCmd(ParentPlatform platform, DeviceChannel deviceChannel, String sn, boolean result, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
+ if (platform == null || deviceChannel == null) {
+ return;
+ }
+ String characterSet = platform.getCharacterSet();
+ StringBuffer mediaStatusXml = new StringBuffer(200);
+ mediaStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
+ mediaStatusXml.append("<Notify>\r\n");
+ mediaStatusXml.append("<CmdType>Broadcast</CmdType>\r\n");
+ mediaStatusXml.append("<SN>" + sn + "</SN>\r\n");
+ mediaStatusXml.append("<DeviceID>" + deviceChannel.getChannelId() + "</DeviceID>\r\n");
+ mediaStatusXml.append("<Result>" + (result?"OK":"ERROR") + "</Result>\r\n");
+ mediaStatusXml.append("</Notify>\r\n");
+
+ CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(platform.getDeviceIp(), platform.getTransport());
+
+ SIPRequest messageRequest = (SIPRequest)headerProviderPlatformProvider.createMessageRequest(platform, mediaStatusXml.toString(),
+ SipUtils.getNewFromTag(), SipUtils.getNewViaTag(), callIdHeader);
+
+ sipSender.transmitRequest(platform.getDeviceIp(),messageRequest, errorEvent, okEvent);
+ }
+
+ @Override
+ public void broadcastInviteCmd(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem,
+ SSRCInfo ssrcInfo, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent,
+ SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException {
+ String stream = ssrcInfo.getStream();
+
+ if (platform == null) {
+ return;
+ }
+
+ logger.info("{} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
+ HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
+ subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
+ if (event != null) {
+ event.response(mediaServerItemInUse, json);
+ subscribe.removeSubscribe(hookSubscribe);
+ }
+ });
+ String sdpIp = mediaServerItem.getSdpIp();
+
+ StringBuffer content = new StringBuffer(200);
+ content.append("v=0\r\n");
+ content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");
+ content.append("s=Play\r\n");
+ content.append("c=IN IP4 " + sdpIp + "\r\n");
+ content.append("t=0 0\r\n");
+
+ if ("TCP-PASSIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
+ content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 8 96\r\n");
+ } else if ("TCP-ACTIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
+ content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 8 96\r\n");
+ } else if ("UDP".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
+ content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 8 96\r\n");
+ }
+
+ content.append("a=recvonly\r\n");
+ content.append("a=rtpmap:8 PCMA/8000\r\n");
+ content.append("a=rtpmap:96 PS/90000\r\n");
+ if ("TCP-PASSIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
+ content.append("a=setup:passive\r\n");
+ content.append("a=connection:new\r\n");
+ }else if ("TCP-ACTIVE".equalsIgnoreCase(userSetting.getBroadcastForPlatform())) {
+ content.append("a=setup:active\r\n");
+ content.append("a=connection:new\r\n");
+ }
+
+ content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
+ CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getTransport());
+
+ Request request = headerProviderPlatformProvider.createInviteRequest(platform, channelId,
+ content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),
+ callIdHeader ,platform.getTransport());
+ sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> {
+ streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
+ mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
+ errorEvent.response(e);
+ }), e -> {
+ // 杩欓噷涓轰緥閬垮厤涓�涓�氶亾鐨勭偣鎾彧鏈変竴涓猚allID杩欎釜鍙傛暟浣跨敤涓�涓浐瀹氬��
+ ResponseEvent responseEvent = (ResponseEvent) e.event;
+ SIPResponse response = (SIPResponse) responseEvent.getResponse();
+ streamSession.put(platform.getServerGBId(), channelId, callIdHeader.getCallId(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play);
+ okEvent.response(e);
+ });
+ }
}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
index c5220a9..10b0daa 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -16,8 +16,6 @@
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
-import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.service.IMediaServerService;
@@ -40,8 +38,6 @@
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import java.text.ParseException;
-import java.util.HashMap;
-import java.util.Map;
/**
* SIP鍛戒护绫诲瀷锛� ACK璇锋眰
@@ -123,68 +119,31 @@
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
logger.info("鏀跺埌ACK锛宺tp/{}寮�濮嬪悜涓婄骇鎺ㄦ祦, 鐩爣={}:{}锛孲SRC={}, RTCP={}", sendRtpItem.getStreamId(),
sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
- Map<String, Object> param = new HashMap<>(12);
- param.put("vhost","__defaultVhost__");
- param.put("app",sendRtpItem.getApp());
- param.put("stream",sendRtpItem.getStreamId());
- param.put("ssrc", sendRtpItem.getSsrc());
- param.put("src_port", sendRtpItem.getLocalPort());
- param.put("pt", sendRtpItem.getPt());
- param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
- param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
- if (!sendRtpItem.isTcp()) {
- // udp妯″紡涓嬪紑鍚痳tcp淇濇椿
- param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
- }
-
if (mediaInfo == null) {
RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),
sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {
- startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, json, param, callIdHeader);
+ startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, json, callIdHeader);
});
- } else {
- // 濡傛灉鏄潪涓ユ牸妯″紡锛岄渶瑕佸叧闂鍙e崰鐢�
- JSONObject startSendRtpStreamResult = null;
- if (sendRtpItem.getLocalPort() != 0) {
- HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(sendRtpItem.getSsrc(), null, mediaInfo.getId());
- hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
- if (zlmrtpServerFactory.releasePort(mediaInfo, sendRtpItem.getSsrc())) {
- if (sendRtpItem.isTcpActive()) {
- startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
- }else {
- param.put("is_udp", is_Udp);
- param.put("dst_url", sendRtpItem.getIp());
- param.put("dst_port", sendRtpItem.getPort());
- startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
- }
- }
- }else {
- if (sendRtpItem.isTcpActive()) {
- startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
- }else {
- param.put("is_udp", is_Udp);
- param.put("dst_url", sendRtpItem.getIp());
- param.put("dst_port", sendRtpItem.getPort());
- startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
- }
- }
+ }else {
+ JSONObject startSendRtpStreamResult = zlmrtpServerFactory.startSendRtp(mediaInfo, sendRtpItem);
if (startSendRtpStreamResult != null) {
- startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, startSendRtpStreamResult, param, callIdHeader);
+ startSendRtpStreamHand(evt, sendRtpItem, parentPlatform, startSendRtpStreamResult, callIdHeader);
}
}
}
+
private void startSendRtpStreamHand(RequestEvent evt, SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
- JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader) {
+ JSONObject jsonObject, CallIdHeader callIdHeader) {
if (jsonObject == null) {
logger.error("RTP鎺ㄦ祦澶辫触: 璇锋鏌LM鏈嶅姟");
} else if (jsonObject.getInteger("code") == 0) {
logger.info("璋冪敤ZLM鎺ㄦ祦鎺ュ彛, 缁撴灉锛� {}", jsonObject);
- logger.info("RTP鎺ㄦ祦鎴愬姛[ {}/{} ]锛寋}->{}:{}, " ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
+ logger.info("RTP鎺ㄦ祦鎴愬姛[ {}/{} ]锛寋}->{}:{}, " ,sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getIp(), sendRtpItem.getPort());
} else {
- logger.error("RTP鎺ㄦ祦澶辫触: {}, 鍙傛暟锛歿}",jsonObject.getString("msg"), JSON.toJSONString(param));
+ logger.error("RTP鎺ㄦ祦澶辫触: {}, 鍙傛暟锛歿}",jsonObject.getString("msg"), JSON.toJSONString(sendRtpItem));
if (sendRtpItem.isOnlyAudio()) {
Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
@@ -193,7 +152,7 @@
cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null);
} catch (SipException | ParseException | InvalidArgumentException |
SsrcTransactionNotFoundException e) {
- logger.error("[鍛戒护鍙戦�佸け璐 鍋滄璇煶瀵硅: {}", e.getMessage());
+ logger.error("[鍛戒护鍙戦�佸け璐 鍋滄璇煶鍠婅瘽: {}", e.getMessage());
}
}
}else {
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
index e31995c..6e188a5 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -201,7 +201,7 @@
MediaServerItem mediaServerItem = null;
StreamPushItem streamPushItem = null;
- StreamProxyItem proxyByAppAndStream =null;
+ StreamProxyItem proxyByAppAndStream = null;
// 涓嶆槸閫氶亾鍙兘鏄洿鎾祦
if (channel != null && gbStream == null) {
// 閫氶亾瀛樺湪锛屽彂100锛孴RYING
@@ -1001,7 +1001,7 @@
String stream = device.getDeviceId() + "_" + audioBroadcastCatch.getChannelId();
CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
- sendRtpItem.setPlayType(InviteStreamType.TALK);
+ sendRtpItem.setPlayType(InviteStreamType.BROADCAST);
sendRtpItem.setCallId(callIdHeader.getCallId());
sendRtpItem.setPlatformId(requesterId);
sendRtpItem.setStatus(1);
@@ -1012,6 +1012,7 @@
sendRtpItem.setRtcp(false);
sendRtpItem.setOnlyAudio(true);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
+
Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream);
if (streamReady) {
@@ -1084,7 +1085,7 @@
audioBroadcastManager.update(audioBroadcastCatch);
} catch (SipException | InvalidArgumentException | ParseException | SdpParseException e) {
- logger.error("[鍛戒护鍙戦�佸け璐 璇煶瀵硅 鍥炲200OK锛圫DP锛�: {}", e.getMessage());
+ logger.error("[鍛戒护鍙戦�佸け璐 璇煶鍠婅瘽 鍥炲200OK锛圫DP锛�: {}", e.getMessage());
}
return sipResponse;
}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java
new file mode 100644
index 0000000..353aaf2
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java
@@ -0,0 +1,200 @@
+package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
+import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
+import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
+import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
+import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
+import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IDeviceService;
+import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.service.IPlatformService;
+import com.genersoft.iot.vmp.service.IPlayService;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
+import gov.nist.javax.sip.message.SIPRequest;
+import org.dom4j.Element;
+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 javax.sip.InvalidArgumentException;
+import javax.sip.RequestEvent;
+import javax.sip.SipException;
+import javax.sip.message.Response;
+import java.text.ParseException;
+
+/**
+ * 鐘舵�佷俊鎭�(蹇冭烦)鎶ラ��
+ */
+@Component
+public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
+
+ private Logger logger = LoggerFactory.getLogger(BroadcastNotifyMessageHandler.class);
+ private final static String cmdType = "Broadcast";
+
+ @Autowired
+ private NotifyMessageHandler notifyMessageHandler;
+
+ @Autowired
+ private IVideoManagerStorage storage;
+
+ @Autowired
+ private ISIPCommanderForPlatform commanderForPlatform;
+
+ @Autowired
+ private IMediaServerService mediaServerService;
+
+ @Autowired
+ private IPlayService playService;
+
+ @Autowired
+ private IDeviceService deviceService;
+
+ @Autowired
+ private IPlatformService platformService;
+
+ @Autowired
+ private AudioBroadcastManager audioBroadcastManager;
+
+ @Autowired
+ private ZLMRTPServerFactory zlmrtpServerFactory;
+
+ @Autowired
+ private IRedisCatchStorage redisCatchStorage;
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ notifyMessageHandler.addHandler(cmdType, this);
+ }
+
+ @Override
+ public void handForDevice(RequestEvent evt, Device device, Element element) {
+
+ }
+
+ @Override
+ public void handForPlatform(RequestEvent evt, ParentPlatform platform, Element rootElement) {
+ // 鏉ヨ嚜涓婄骇骞冲彴鐨勮闊冲枈璇濊姹�
+ SIPRequest request = (SIPRequest) evt.getRequest();
+ try {
+ Element snElement = rootElement.element("SN");
+ if (snElement == null) {
+ responseAck(request, Response.BAD_REQUEST, "sn must not null");
+ return;
+ }
+ String sn = snElement.getText();
+ Element targetIDElement = rootElement.element("TargetID");
+ if (targetIDElement == null) {
+ responseAck(request, Response.BAD_REQUEST, "TargetID must not null");
+ return;
+ }
+ String targetId = targetIDElement.getText();
+
+
+ logger.info("[鍥芥爣绾ц仈 璇煶鍠婅瘽] platform: {}, channel: {}", platform.getServerGBId(), targetId);
+
+ DeviceChannel deviceChannel = storage.queryChannelInParentPlatform(platform.getServerGBId(), targetId);
+ if (deviceChannel == null) {
+ responseAck(request, Response.NOT_FOUND, "TargetID not found");
+ return;
+ }
+ // 鍚戜笅绾у彂閫佽闊崇殑鍠婅瘽璇锋眰
+ Device device = deviceService.getDevice(deviceChannel.getDeviceId());
+ if (device == null) {
+ responseAck(request, Response.NOT_FOUND, "device not found");
+ return;
+ }
+ responseAck(request, Response.OK);
+
+ // 鏌ョ湅璇煶閫氶亾鏄惁宸茬粡寤虹珛骞朵笖宸茬粡鍦ㄤ娇鐢�
+ if (playService.audioBroadcastInUse(device, targetId)) {
+ commanderForPlatform.broadcastResultCmd(platform, deviceChannel, sn, false,null, null);
+ return;
+ }
+
+ MediaServerItem mediaServerForMinimumLoad = mediaServerService.getMediaServerForMinimumLoad();
+ commanderForPlatform.broadcastResultCmd(platform, deviceChannel, sn, true, eventResult->{
+ logger.info("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 鍥炲澶辫触 platform锛� {}锛� 閿欒锛歿}/{}", platform.getServerGBId(), eventResult.statusCode, eventResult.msg);
+ }, eventResult->{
+ // 娑堟伅鍙戦�佹垚鍔燂紝 鍚戜笂绾у彂閫乮nvite锛岃幏鍙栨帹娴�
+ try {
+ platformService.broadcastInvite(platform, deviceChannel.getChannelId(), mediaServerForMinimumLoad, (mediaServerItem, response)->{
+ // 涓婄骇骞冲彴鎺ㄦ祦鎴愬姛
+ String app = response.getString("app");
+ String stream = response.getString("stream");
+ AudioBroadcastCatch broadcastCatch = audioBroadcastManager.get(device.getDeviceId(), targetId);
+ if (broadcastCatch != null ) {
+ if (playService.audioBroadcastInUse(device, targetId)) {
+ logger.info("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 璁惧姝f鍦ㄤ娇鐢ㄤ腑 platform锛� {}锛� channel: {}",
+ platform.getServerGBId(), deviceChannel.getChannelId());
+ // 鏌ョ湅璇煶閫氶亾宸茬粡寤虹珛涓斿凡缁忓崰鐢� 鍥炲BYE
+ try {
+ platformService.stopBroadcast(platform, deviceChannel.getChannelId(), stream);
+ } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException |
+ SipException e) {
+ logger.info("[娑堟伅鍙戦�佸け璐 鍥芥爣绾ц仈 璇煶鍠婅瘽 platform锛� {}锛� channel: {}", platform.getServerGBId(), deviceChannel.getChannelId());
+ }
+ }else {
+ // 鏌ョ湅璇煶閫氶亾宸茬粡寤虹珛浣嗘槸鏈崰鐢�
+ broadcastCatch.setApp(app);
+ broadcastCatch.setStream(stream);
+ broadcastCatch.setMediaServerItem(mediaServerItem);
+ audioBroadcastManager.update(broadcastCatch);
+ // 鎺ㄦ祦鍒拌澶�
+ SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, targetId, stream, null);
+ if (sendRtpItem == null) {
+ logger.warn("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 寮傚父锛屾湭鎵惧埌鍙戞祦淇℃伅锛� channelId: {}, stream: {}", targetId, stream);
+ logger.info("[鍥芥爣绾ц仈] 璇煶鍠婅瘽 閲嶆柊寮�濮嬶紝channelId: {}, stream: {}", targetId, stream);
+ try {
+ playService.audioBroadcastCmd(device, targetId, mediaServerItem, app, stream, 60, true, msg -> {
+ logger.info("[璇煶鍠婅瘽] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", device.getDeviceId(), targetId);
+ });
+ } catch (SipException | InvalidArgumentException | ParseException e) {
+ logger.info("[娑堟伅鍙戦�佸け璐 鍥芥爣绾ц仈 璇煶鍠婅瘽 platform锛� {}", platform.getServerGBId());
+ }
+ }else {
+ // 鍙戞祦
+ JSONObject jsonObject = zlmrtpServerFactory.startSendRtp(mediaServerItem, sendRtpItem);
+ if (jsonObject != null && jsonObject.getInteger("code") == 0 ) {
+ logger.info("[璇煶鍠婅瘽] 鑷姩鎺ㄦ祦鎴愬姛, device: {}, channel: {}", device.getDeviceId(), targetId);
+ }else {
+ logger.info("[璇煶鍠婅瘽] 鎺ㄦ祦澶辫触, 缁撴灉锛� {}", jsonObject);
+ }
+ }
+ }
+ }else {
+ try {
+ playService.audioBroadcastCmd(device, targetId, mediaServerItem, app, stream, 60, true, msg -> {
+ logger.info("[璇煶鍠婅瘽] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", device.getDeviceId(), targetId);
+ });
+ } catch (SipException | InvalidArgumentException | ParseException e) {
+ logger.info("[娑堟伅鍙戦�佸け璐 鍥芥爣绾ц仈 璇煶鍠婅瘽 platform锛� {}", platform.getServerGBId());
+ }
+ }
+
+ }, eventResultForBroadcastInvite -> {
+ // 鏀跺埌閿欒
+ logger.info("[鍥芥爣绾ц仈-璇煶鍠婅瘽] 涓庝笅绾ч�氶亾寤虹珛澶辫触 device: {}, channel: {}锛� 閿欒锛歿}/{}", device.getDeviceId(),
+ targetId, eventResultForBroadcastInvite.statusCode, eventResultForBroadcastInvite.msg);
+ }, (code, msg)->{
+ // 瓒呮椂
+ logger.info("[鍥芥爣绾ц仈-璇煶鍠婅瘽] 涓庝笅绾ч�氶亾寤虹珛瓒呮椂 device: {}, channel: {}锛� 閿欒锛歿}/{}", device.getDeviceId(),
+ targetId, code, msg);
+ });
+ } catch (SipException | InvalidArgumentException | ParseException e) {
+ logger.info("[娑堟伅鍙戦�佸け璐 鍥芥爣绾ц仈 璇煶鍠婅瘽 invite娑堟伅 platform锛� {}", platform.getServerGBId());
+ }
+ });
+ } catch (SipException | InvalidArgumentException | ParseException e) {
+ logger.info("[娑堟伅鍙戦�佸け璐 鍥芥爣绾ц仈 璇煶鍠婅瘽 platform锛� {}", platform.getServerGBId());
+ }
+
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
index 56fb789..2cf2072 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
@@ -1,17 +1,14 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
-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;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
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.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
-import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import gov.nist.javax.sip.message.SIPRequest;
import org.dom4j.Element;
import org.slf4j.Logger;
@@ -52,26 +49,13 @@
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
try {
String channelId = getText(rootElement, "DeviceID");
- String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId() + channelId;
-
- // 姝ゅ鏄鏈钩鍙板彂鍑築roadcast鎸囦护鐨勫簲绛�
- JSONObject json = new JSONObject();
- XmlUtil.node2Json(rootElement, json);
- if (logger.isDebugEnabled()) {
- logger.debug(json.toJSONString());
- }
- RequestMessage msg = new RequestMessage();
- msg.setKey(key);
- msg.setData(json);
- deferredResultHolder.invokeAllResult(msg);
-
-
if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
// 鍥炲410
responseAck((SIPRequest) evt.getRequest(), Response.GONE);
return;
}
- logger.info("鏀跺埌璇煶骞挎挱鐨勫洖澶嶏細{}/{}", device.getDeviceId(), channelId );
+ String result = getText(rootElement, "Result");
+ logger.info("鏀跺埌璇煶骞挎挱鐨勫洖澶� {}锛歿}/{}", result, device.getDeviceId(), channelId );
AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), channelId);
audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.WaiteInvite);
audioBroadcastManager.update(audioBroadcastCatch);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
index d0ba97e..16fa6d8 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
@@ -1,39 +1,24 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
-import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.SipLayer;
-import com.genersoft.iot.vmp.gb28181.bean.Device;
-import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
-import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
-import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
-import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
-import com.genersoft.iot.vmp.service.IDeviceService;
-import com.genersoft.iot.vmp.utils.GitUtil;
import gov.nist.javax.sip.ResponseEventExt;
-import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.message.SIPResponse;
-import gov.nist.javax.sip.stack.SIPClientTransaction;
-import gov.nist.javax.sip.stack.SIPDialog;
-import gov.nist.javax.sip.stack.SIPTransaction;
-import gov.nist.javax.sip.stack.SIPTransactionImpl;
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.stereotype.Component;
import javax.sdp.SdpFactory;
import javax.sdp.SdpParseException;
import javax.sdp.SessionDescription;
-import javax.sip.*;
-import javax.sip.address.Address;
+import javax.sip.InvalidArgumentException;
+import javax.sip.ResponseEvent;
+import javax.sip.SipException;
import javax.sip.address.SipURI;
-import javax.sip.header.CSeqHeader;
-import javax.sip.header.UserAgentHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
@@ -104,6 +89,7 @@
} else {
sdp = SdpFactory.getInstance().createSessionDescription(contentString);
}
+ // 鏌ョ湅鏄惁鏄潵鑷澶囩殑锛屾鏄洖澶�
SipURI requestUri = sipLayer.getSipFactory().createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort());
Request reqAck = headerProvider.createAckRequest(response.getLocalAddress().getHostAddress(), requestUri, response);
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
index 88d7e14..51ff7ad 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -287,15 +287,19 @@
logger.info("[ZLM HOOK] 娴佹敞閿�, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
}
+ JSONObject ret = new JSONObject();
+ ret.put("code", 0);
+ ret.put("msg", "success");
JSONObject json = (JSONObject) JSON.toJSON(param);
+ MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
+ if (mediaInfo == null) {
+ return ret;
+ }
taskExecutor.execute(()-> {
ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
- if (subscribe != null) {
- MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
- if (mediaInfo != null) {
- subscribe.response(mediaInfo, json);
- }
+ if (subscribe != null ) {
+ subscribe.response(mediaInfo, json);
}
// 娴佹秷澶辩Щ闄edis play
List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
@@ -343,7 +347,7 @@
}
}
}else if ("broadcast".equals(param.getApp())){
- // 璇煶瀵硅鎺ㄦ祦 stream闇�瑕佹弧瓒虫牸寮廳eviceId_channelId
+ // 璇煶鍠婅瘽鎺ㄦ祦 stream闇�瑕佹弧瓒虫牸寮廳eviceId_channelId
if (param.isRegist() && param.getStream().indexOf("_") > 0) {
String[] streamArray = param.getStream().split("_");
if (streamArray.length == 2) {
@@ -359,53 +363,38 @@
if (sendRtpItem == null) {
// TODO 鍙兘鏁版嵁閿欒锛岄噸鏂板紑鍚闊抽�氶亾
}else {
- String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
- MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
- logger.info("rtp/{}寮�濮嬪悜涓婄骇鎺ㄦ祦, 鐩爣={}:{}锛孲SRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
- 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, sendParam);
- } else {
- 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);
+ JSONObject jsonObject = zlmrtpServerFactory.startSendRtp(mediaInfo, sendRtpItem);
+ if (jsonObject != null && jsonObject.getInteger("code") == 0 ) {
+ logger.info("[璇煶鍠婅瘽] 鑷姩鎺ㄦ祦鎴愬姛, device: {}, channel: {}", device.getDeviceId(), channelId);
}else {
- logger.info("[璇煶瀵硅] 鎺ㄦ祦澶辫触, 缁撴灉锛� {}", jsonObject);
+ logger.info("[璇煶鍠婅瘽] 鎺ㄦ祦澶辫触, 缁撴灉锛� {}", jsonObject);
}
}
}else {
- // 寮�鍚闊冲璁查�氶亾
+ // 寮�鍚闊冲枈璇濋�氶亾
try {
- playService.audioBroadcastCmd(device, channelId, 60, (msg)->{
- logger.info("[璇煶瀵硅] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", deviceId, channelId);
+ playService.audioBroadcastCmd(device, channelId, mediaInfo, param.getApp(), param.getStream(),60, false, (msg)->{
+ logger.info("[璇煶鍠婅瘽] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", deviceId, channelId);
});
} catch (InvalidArgumentException | ParseException | SipException e) {
- logger.error("[鍛戒护鍙戦�佸け璐 璇煶瀵硅: {}", e.getMessage());
+ logger.error("[鍛戒护鍙戦�佸け璐 璇煶鍠婅瘽: {}", e.getMessage());
}
}
+ }else {
+ logger.info("[璇煶鍠婅瘽] 鎺ㄦ祦鎸囧悜鐨劼烽�氶亾{}鏈壘鍒�", channelId);
}
+ }else {
+ logger.info("[璇煶鍠婅瘽] 鎺ㄦ祦鎸囧悜鐨劼疯澶噞}鏈壘鍒�", deviceId);
}
+ }else {
+ logger.info("[璇煶鍠婅瘽] 鎺ㄦ祦鏍煎紡鏈夎, 鏍煎紡涓猴細 broadcast/璁惧缂栧彿_閫氶亾缂栧彿 ");
}
}
}else if ("talk".equals(param.getApp())){
- // 璇煶瀵硅鎺ㄦ祦 stream闇�瑕佹弧瓒虫牸寮廳eviceId_channelId
+ // 璇煶鍠婅瘽鎺ㄦ祦 stream闇�瑕佹弧瓒虫牸寮廳eviceId_channelId
if (param.isRegist() && param.getStream().indexOf("_") > 0) {
String[] streamArray = param.getStream().split("_");
if (streamArray.length == 2) {
@@ -421,33 +410,11 @@
if (sendRtpItem == null) {
// TODO 鍙兘鏁版嵁閿欒锛岄噸鏂板紑鍚闊抽�氶亾
}else {
- MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
logger.info("rtp/{}寮�濮嬪悜涓婄骇鎺ㄦ祦, 鐩爣={}:{}锛孲SRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
- 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, sendParam);
- } else {
- 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);
- }
+ zlmrtpServerFactory.startSendRtp(mediaInfo, sendRtpItem);
}
}else {
- // 寮�鍚闊冲璁查�氶亾
+ // 寮�鍚闊冲枈璇濋�氶亾
MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
playService.talk(mediaServerItem, device, channelId, (mediaServer, jsonObject)->{
System.out.println("寮�濮嬫帹娴�");
@@ -549,9 +516,7 @@
}
}
- JSONObject ret = new JSONObject();
- ret.put("code", 0);
- ret.put("msg", "success");
+
return ret;
}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
index 4a6a94a..c7d9966 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -348,4 +348,52 @@
return result;
}
+ public JSONObject startSendRtp(MediaServerItem mediaInfo, SendRtpItem sendRtpItem) {
+ String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
+ logger.info("rtp/{}寮�濮嬪悜涓婄骇鎺ㄦ祦, 鐩爣={}:{}锛孲SRC={}", 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");
+ if (!sendRtpItem.isTcp()) {
+ // udp妯″紡涓嬪紑鍚痳tcp淇濇椿
+ param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
+ }
+
+ if (mediaInfo == null) {
+ return null;
+ }
+ // 濡傛灉鏄潪涓ユ牸妯″紡锛岄渶瑕佸叧闂鍙e崰鐢�
+ JSONObject startSendRtpStreamResult = null;
+ if (sendRtpItem.getLocalPort() != 0) {
+ HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(sendRtpItem.getSsrc(), null, mediaInfo.getId());
+ hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
+ if (releasePort(mediaInfo, sendRtpItem.getSsrc())) {
+ if (sendRtpItem.isTcpActive()) {
+ startSendRtpStreamResult = startSendRtpPassive(mediaInfo, param);
+ System.out.println(JSON.toJSON(param));
+ }else {
+ param.put("is_udp", is_Udp);
+ param.put("dst_url", sendRtpItem.getIp());
+ param.put("dst_port", sendRtpItem.getPort());
+ startSendRtpStreamResult = startSendRtpStream(mediaInfo, param);
+ }
+ }
+ }else {
+ if (sendRtpItem.isTcpActive()) {
+ startSendRtpStreamResult = startSendRtpPassive(mediaInfo, param);
+ }else {
+ param.put("is_udp", is_Udp);
+ param.put("dst_url", sendRtpItem.getIp());
+ param.put("dst_port", sendRtpItem.getPort());
+ startSendRtpStreamResult = startSendRtpStream(mediaInfo, param);
+ }
+ }
+ return startSendRtpStreamResult;
+ }
}
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java
index 17f8b37..be8a8f5 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java
@@ -1,7 +1,16 @@
package com.genersoft.iot.vmp.service;
+import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
+import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
import com.github.pagehelper.PageInfo;
+
+import javax.sip.InvalidArgumentException;
+import javax.sip.SipException;
+import java.text.ParseException;
/**
* 鍥芥爣骞冲彴鐨勪笟鍔$被
@@ -48,4 +57,23 @@
* @param platformId 骞冲彴
*/
void sendNotifyMobilePosition(String platformId);
+
+ /**
+ * 鍚戜笂绾у彂閫佽闊冲枈璇濈殑娑堟伅
+ * @param platform 骞冲彴
+ * @param channelId 閫氶亾
+ * @param hookEvent hook浜嬩欢
+ * @param errorEvent 淇′护閿欒浜嬩欢
+ * @param timeoutCallback 瓒呮椂浜嬩欢
+ */
+ void broadcastInvite(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem, ZlmHttpHookSubscribe.Event hookEvent,
+ SipSubscribe.Event errorEvent, InviteTimeOutCallback timeoutCallback) throws InvalidArgumentException, ParseException, SipException;
+
+ /**
+ * 璇煶鍠婅瘽鍥炲BYE
+ * @param platform 骞冲彴
+ * @param channelId 閫氶亾
+ * @param stream 娴佷俊鎭�
+ */
+ void stopBroadcast(ParentPlatform platform, String channelId, String stream )throws InvalidArgumentException, ParseException, SsrcTransactionNotFoundException, SipException;
}
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
index 4ab2f4a..3f7e13d 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -53,10 +53,13 @@
void zlmServerOnline(String mediaServerId);
- AudioBroadcastResult audioBroadcast(Device device, String channelId);
- void stopAudioBroadcast(String deviceId, String channelId);
+ AudioBroadcastResult audioBroadcastInfo(Device device, String channelId);
- void audioBroadcastCmd(Device device, String channelId, int timeout, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
+ boolean audioBroadcastCmd(Device device, String channelId, MediaServerItem mediaServerItem, String app, String stream, int timeout, boolean isFromPlatform, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
+
+ boolean audioBroadcastInUse(Device device, String channelId);
+
+ void stopAudioBroadcast(String deviceId, String channelId);
void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
index fbc507a..5b0f67b 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
@@ -1,15 +1,25 @@
package com.genersoft.iot.vmp.service.impl;
+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.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.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
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;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IPlatformService;
+import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
+import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
+import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper;
@@ -21,11 +31,13 @@
import org.springframework.stereotype.Service;
import javax.sip.InvalidArgumentException;
+import javax.sip.ResponseEvent;
import javax.sip.SipException;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
/**
* @author lin
@@ -64,6 +76,16 @@
@Autowired
private UserSetting userSetting;
+
+ @Autowired
+ private ZlmHttpHookSubscribe subscribe;
+
+ @Autowired
+ private VideoStreamSessionManager streamSession;
+
+
+ @Autowired
+ private IPlayService playService;
@@ -295,4 +317,137 @@
}
}
}
+
+ @Override
+ public void broadcastInvite(ParentPlatform platform, String channelId, MediaServerItem mediaServerItem, ZlmHttpHookSubscribe.Event hookEvent,
+ SipSubscribe.Event errorEvent, InviteTimeOutCallback timeoutCallback) throws InvalidArgumentException, ParseException, SipException {
+
+ if (mediaServerItem == null) {
+ logger.info("[鍥芥爣绾ц仈] 璇煶鍠婅瘽鏈壘鍒板彲鐢ㄧ殑zlm. platform: {}", platform.getServerGBId());
+ return;
+ }
+ StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(platform.getServerGBId(), channelId);
+ if (streamInfo != null) {
+ // 濡傛灉zlm涓嶅瓨鍦ㄨ繖涓祦锛屽垯鍒犻櫎鏁版嵁鍗冲彲
+ MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(streamInfo.getMediaServerId());
+ if (mediaServerItemForStreamInfo != null) {
+ Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItemForStreamInfo, streamInfo.getApp(), streamInfo.getStream());
+ if (!ready) {
+ // 閿欒瀛樺湪浜巖edis涓殑鏁版嵁
+ redisCatchStorage.stopPlay(streamInfo);
+ }else {
+ // 娴佺‘瀹炲皻鍦ㄦ帹娴侊紝鐩存帴鍥炶皟缁撴灉
+ JSONObject json = new JSONObject();
+ json.put("app", streamInfo.getApp());
+ json.put("stream", streamInfo.getStream());
+ hookEvent.response(mediaServerItemForStreamInfo, json);
+ return;
+ }
+ }
+ }
+
+ String streamId = null;
+ if (mediaServerItem.isRtpEnable()) {
+ streamId = String.format("%s_%s", platform.getServerGBId(), channelId);
+ }
+ // 榛樿涓嶈繘琛孲SRC鏍¢獙锛� TODO 鍚庣画鍙敼涓洪厤缃�
+ boolean ssrcCheck = false;
+ SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, ssrcCheck, false);
+ if (ssrcInfo == null || ssrcInfo.getPort() < 0) {
+ logger.info("[鍥芥爣绾ц仈] 鍙戣捣璇煶鍠婅瘽 寮�鍚鍙g洃鍚け璐ワ紝 platform: {}, channel锛� {}", platform.getServerGBId(), channelId);
+ errorEvent.response(new SipSubscribe.EventResult(-1, "绔彛鐩戝惉澶辫触"));
+ return;
+ }
+ logger.info("[鍥芥爣绾ц仈] 鍙戣捣璇煶鍠婅瘽 deviceId: {}, channelId: {},鏀舵祦绔彛锛� {}, 鏀舵祦妯″紡锛歿}, SSRC: {}, SSRC鏍¢獙锛歿}",
+ platform.getServerGBId(), channelId, ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), ssrcCheck);
+
+ String timeOutTaskKey = UUID.randomUUID().toString();
+ dynamicTask.startDelay(timeOutTaskKey, () -> {
+ // 鎵ц瓒呮椂浠诲姟鏃舵煡璇㈡槸鍚﹀凡缁忔垚鍔燂紝鎴愬姛浜嗗垯涓嶆墽琛岃秴鏃朵换鍔★紝闃叉瓒呮椂浠诲姟鍙栨秷澶辫触鐨勬儏鍐�
+ if (redisCatchStorage.queryPlayByDevice(platform.getServerGBId(), channelId) == null) {
+ logger.info("[鍥芥爣绾ц仈] 鍙戣捣璇煶鍠婅瘽 鏀舵祦瓒呮椂 deviceId: {}, channelId: {}锛岀鍙o細{}, SSRC: {}", platform.getServerGBId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc());
+ // 鐐规挱瓒呮椂鍥炲BYE 鍚屾椂閲婃斁ssrc浠ュ強姝ゆ鐐规挱鐨勮祫婧�
+ try {
+ commanderForPlatform.streamByeCmd(platform, channelId, ssrcInfo.getStream(), null, null);
+ } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
+ logger.error("[鐐规挱瓒呮椂]锛� 鍙戦�丅YE澶辫触 {}", e.getMessage());
+ } finally {
+ timeoutCallback.run(1, "鏀舵祦瓒呮椂");
+ mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
+ mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
+ streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
+ mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
+ }
+ }
+ }, userSetting.getPlayTimeout());
+ commanderForPlatform.broadcastInviteCmd(platform, channelId, mediaServerItem, ssrcInfo, (mediaServerItemForInvite, response)->{
+ dynamicTask.stop(timeOutTaskKey);
+ // hook鍝嶅簲
+ playService.onPublishHandlerForPlay(mediaServerItemForInvite, response, platform.getServerGBId(), channelId);
+ // 鏀跺埌娴�
+ if (hookEvent != null) {
+ hookEvent.response(mediaServerItem, response);
+ }
+ }, event -> {
+ // 鏀跺埌200OK 妫�娴媠src鏄惁鏈夊彉鍖栵紝闃叉涓婄骇鑷畾涔変簡ssrc
+ ResponseEvent responseEvent = (ResponseEvent) event.event;
+ String contentString = new String(responseEvent.getResponse().getRawContent());
+ // 鑾峰彇ssrc
+ int ssrcIndex = contentString.indexOf("y=");
+ // 妫�鏌ユ槸鍚︽湁y瀛楁
+ if (ssrcIndex >= 0) {
+ //ssrc瑙勫畾闀垮害涓�10瀛楄妭锛屼笉鍙栦綑涓嬮暱搴︿互閬垮厤鍚庣画杩樻湁鈥渇=鈥濆瓧娈� TODO 鍚庣画瀵逛笉瑙勮寖鐨勯潪10浣峴src鍏煎
+ String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
+ // 鏌ヨ鍒皊src涓嶄竴鑷翠笖寮�鍚簡ssrc鏍¢獙鍒欓渶瑕侀拡瀵瑰鐞�
+ if (ssrcInfo.getSsrc().equals(ssrcInResponse) || ssrcCheck) {
+ return;
+ }
+ logger.info("[鐐规挱娑堟伅] 鏀跺埌invite 200, 鍙戠幇涓嬬骇鑷畾涔変簡ssrc: {}", ssrcInResponse);
+ if (!mediaServerItem.isRtpEnable()) {
+ logger.info("[鐐规挱娑堟伅] SSRC淇 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
+
+ if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
+ // ssrc 涓嶅彲鐢�
+ // 閲婃斁ssrc
+ mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
+ streamSession.remove(platform.getServerGBId(), channelId, ssrcInfo.getStream());
+ event.msg = "涓嬬骇鑷畾涔変簡ssrc,浣嗘槸姝src涓嶅彲鐢�";
+ event.statusCode = 400;
+ errorEvent.response(event);
+ return;
+ }
+
+ // 鍗曠鍙fā寮弒treamId涔熸湁鍙樺寲锛岄渶瑕侀噸鏂拌缃洃鍚�
+ if (!mediaServerItem.isRtpEnable()) {
+ // 娣诲姞璁㈤槄
+ HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
+ subscribe.removeSubscribe(hookSubscribe);
+ hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
+ subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
+ logger.info("[ZLM HOOK] ssrc淇鍚庢敹鍒拌闃呮秷鎭細 " + response.toJSONString());
+ dynamicTask.stop(timeOutTaskKey);
+ // hook鍝嶅簲
+ playService.onPublishHandlerForPlay(mediaServerItemInUse, response, platform.getServerGBId(), channelId);
+ hookEvent.response(mediaServerItemInUse, response);
+ });
+ }
+ // 鍏抽棴rtp server
+ mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
+ // 閲嶆柊寮�鍚痵src server
+ mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, false, false, ssrcInfo.getPort());
+
+ }
+ }
+ }, eventResult -> {
+ // 鏀跺埌閿欒鍥炲
+ if (errorEvent != null) {
+ errorEvent.response(eventResult);
+ }
+ });
+ }
+
+ @Override
+ public void stopBroadcast(ParentPlatform platform, String channelId, String stream) throws InvalidArgumentException, ParseException, SsrcTransactionNotFoundException, SipException {
+ commanderForPlatform.streamByeCmd(platform, channelId, stream, null, null);
+ }
}
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
index 32f0364..5e62981 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -987,7 +987,7 @@
}
@Override
- public AudioBroadcastResult audioBroadcast(Device device, String channelId) {
+ public AudioBroadcastResult audioBroadcastInfo(Device device, String channelId) {
if (device == null || channelId == null) {
return null;
}
@@ -1012,46 +1012,51 @@
}
@Override
- public void audioBroadcastCmd(Device device, String channelId, int timeout, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException {
+ public boolean audioBroadcastCmd(Device device, String channelId, MediaServerItem mediaServerItem, String app, String stream, int timeout, boolean isFromPlatform, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException {
if (device == null || channelId == null) {
- return;
+ return false;
}
logger.info("[璇煶鍠婅瘽] device锛� {}, channel: {}", device.getDeviceId(), channelId);
DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
if (deviceChannel == null) {
logger.warn("寮�鍚闊冲箍鎾殑鏃跺�欐湭鎵惧埌閫氶亾锛� {}", channelId);
event.call("寮�鍚闊冲箍鎾殑鏃跺�欐湭鎵惧埌閫氶亾");
- return;
+ return false;
}
// 鏌ヨ閫氶亾浣跨敤鐘舵��
- if (audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
- SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
- if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) {
- // 鏌ヨ娴佹槸鍚﹀瓨鍦紝涓嶅瓨鍦ㄥ垯璁や负鏄紓甯哥姸鎬�
- MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
- Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, sendRtpItem.getApp(), sendRtpItem.getStreamId());
- if (streamReady) {
- logger.warn("璇煶骞挎挱宸茬粡寮�鍚細 {}", channelId);
- event.call("璇煶骞挎挱宸茬粡寮�鍚�");
- return;
- } else {
- audioBroadcastManager.del(deviceChannel.getDeviceId(), channelId);
- redisCatchStorage.deleteSendRTPServer(device.getDeviceId(), channelId, sendRtpItem.getCallId(), sendRtpItem.getStreamId());
- }
- }
+ if (audioBroadcastInUse(device, channelId)) {
+ return false;
}
// 鍙戦�侀�氱煡
cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> {
// 鍙戦�佹垚鍔�
- AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId, AudioBroadcastCatchStatus.Ready);
- audioBroadcastManager.add(audioBroadcastCatch);
+ AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId, mediaServerItem, app, stream, event, AudioBroadcastCatchStatus.Ready, isFromPlatform);
+ audioBroadcastManager.update(audioBroadcastCatch);
}, eventResultForError -> {
// 鍙戦�佸け璐�
logger.error("璇煶骞挎挱鍙戦�佸け璐ワ細 {}:{}", channelId, eventResultForError.msg);
event.call("璇煶骞挎挱鍙戦�佸け璐�");
stopAudioBroadcast(device.getDeviceId(), channelId);
});
+ return true;
+ }
+
+ @Override
+ public boolean audioBroadcastInUse(Device device, String channelId) {
+ if (audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
+ SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
+ if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) {
+ // 鏌ヨ娴佹槸鍚﹀瓨鍦紝涓嶅瓨鍦ㄥ垯璁や负鏄紓甯哥姸鎬�
+ MediaServerItem mediaServerServiceOne = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+ Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerServiceOne, sendRtpItem.getApp(), sendRtpItem.getStreamId());
+ if (streamReady) {
+ logger.warn("璇煶骞挎挱閫氶亾浣跨敤涓細 {}", channelId);
+ return true;
+ }
+ }
+ }
+ return false;
}
@@ -1075,6 +1080,9 @@
param.put("stream", sendRtpItem.getStreamId());
zlmresTfulUtils.stopSendRtp(mediaInfo, param);
}
+ if (audioBroadcastCatch.isFromPlatform()) {
+ // TODO 鍚戜笂绾у彂閫丅YE缁撴潫璇煶鍠婅瘽
+ }
audioBroadcastManager.del(deviceId, channelId);
}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
index 19b2adc..0747b9a 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -267,7 +267,7 @@
throw new ControllerException(ErrorCode.ERROR400.getCode(), "鏈壘鍒伴�氶亾锛� " + channelId);
}
- return playService.audioBroadcast(device, channelId);
+ return playService.audioBroadcastInfo(device, channelId);
}
diff --git a/src/main/resources/all-application.yml b/src/main/resources/all-application.yml
index ba150fb..92c2acb 100644
--- a/src/main/resources/all-application.yml
+++ b/src/main/resources/all-application.yml
@@ -168,7 +168,7 @@
# 淇濆瓨绉诲姩浣嶇疆鍘嗗彶杞ㄨ抗锛歵rue:淇濈暀鍘嗗彶鏁版嵁锛宖alse:浠呬繚鐣欐渶鍚庣殑浣嶇疆(榛樿)
save-position-history: false
# 鐐规挱绛夊緟瓒呮椂鏃堕棿,鍗曚綅锛氭绉�
- play-timeout: 3000
+ play-timeout: 18000
# 涓婄骇鐐规挱绛夊緟瓒呮椂鏃堕棿,鍗曚綅锛氭绉�
platform-play-timeout: 60000
# 鏄惁寮�鍚帴鍙i壌鏉�
@@ -195,6 +195,8 @@
gb-send-stream-strict: false
# 璁惧涓婄嚎鏃舵槸鍚﹁嚜鍔ㄥ悓姝ラ�氶亾
sync-channel-on-device-online: false
+ # 鍥芥爣绾ц仈璇煶鍠婅瘽鍙戞祦妯″紡 * UDP:udp浼犺緭 TCP-ACTIVE锛歵cp涓诲姩妯″紡 TCP-PASSIVE锛歵cp琚姩妯″紡
+ broadcast-for-platform: UDP
# 鍏抽棴鍦ㄧ嚎鏂囨。锛堢敓浜х幆澧冨缓璁叧闂級
springdoc:
diff --git a/web_src/src/components/dialog/devicePlayer.vue b/web_src/src/components/dialog/devicePlayer.vue
index 89b3e07..cd58f41 100644
--- a/web_src/src/components/dialog/devicePlayer.vue
+++ b/web_src/src/components/dialog/devicePlayer.vue
@@ -279,7 +279,7 @@
</div>
</el-tab-pane>
- <el-tab-pane label="璇煶瀵硅" name="broadcast" >
+ <el-tab-pane label="璇煶鍠婅瘽" name="broadcast" >
<div class="trank" style="text-align: center;">
<el-button @click="broadcastStatusClick()" :type="getBroadcastStatus()" :disabled="broadcastStatus === -2" circle icon="el-icon-microphone" style="font-size: 32px; padding: 24px;margin-top: 24px;"/>
<p>
@@ -854,7 +854,7 @@
if (this.broadcastStatus == -1) {
// 榛樿鐘舵�侊紝 寮�濮�
this.broadcastStatus = 0
- // 鍙戣捣璇煶瀵硅
+ // 鍙戣捣璇煶鍠婅瘽
this.$axios({
method: 'get',
url: '/api/play/broadcast/' + this.deviceId + '/' + this.channelId + "?timeout=30"
@@ -897,7 +897,7 @@
let pushKey = res.data.data.pushKey;
// 鑾峰彇鎺ㄦ祦閴存潈KEY
url += "&sign=" + crypto.createHash('md5').update(pushKey, "utf8").digest('hex')
- console.log("寮�濮嬭闊冲璁诧細 " + url)
+ console.log("寮�濮嬭闊冲枈璇濓細 " + url)
this.broadcastRtc = new ZLMRTCClient.Endpoint({
debug: true, // 鏄惁鎵撳嵃鏃ュ織
zlmsdpUrl: url, //娴佸湴鍧�
@@ -923,7 +923,7 @@
console.error('涓嶆敮鎸亀ebrtc',e)
this.$message({
showClose: true,
- message: '涓嶆敮鎸亀ebrtc, 鏃犳硶杩涜璇煶瀵硅',
+ message: '涓嶆敮鎸亀ebrtc, 鏃犳硶杩涜璇煶鍠婅瘽',
type: 'error'
});
this.broadcastStatus = -1;
--
Gitblit v1.8.0