From 26bdf2e7768ee5dfc400c3970a5aa129fed49453 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: 星期一, 20 三月 2023 15:31:43 +0800 Subject: [PATCH] Merge branch '级联' into main-dev --- 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 | 55 ++ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java | 3 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java | 87 ++++ 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 | 98 ++-- 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 | 75 ++ doc/README.md | 4 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java | 20 src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java | 2 src/main/java/com/genersoft/iot/vmp/service/IPlayService.java | 7 src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java | 156 +++++++ 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 | 5 src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java | 33 + src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java | 2 src/main/resources/all-application.yml | 2 src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java | 77 +++ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java | 1 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java | 6 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java | 59 +- src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java | 124 ++++++ 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 | 9 28 files changed, 970 insertions(+), 174 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 251edf1..811f7e9 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java @@ -55,6 +55,8 @@ private String thirdPartyGBIdReg = "[\\s\\S]*"; + private String broadcastForPlatform = "UDP"; + private List<String> interfaceAuthenticationExcludes = new ArrayList<>(); public Boolean getSavePositionHistory() { @@ -205,6 +207,14 @@ this.syncChannelOnDeviceOnline = syncChannelOnDeviceOnline; } + public String getBroadcastForPlatform() { + return broadcastForPlatform; + } + + public void setBroadcastForPlatform(String broadcastForPlatform) { + this.broadcastForPlatform = broadcastForPlatform; + } + public Boolean getPushStreamAfterAck() { return pushStreamAfterAck; } 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 a57f7a3..4fff352 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 @@ -2,6 +2,7 @@ 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; /** @@ -11,18 +12,24 @@ public class AudioBroadcastCatch { - public AudioBroadcastCatch(String deviceId, - String channelId, - AudioBroadcastCatchStatus status, - MediaServerItem mediaServerItem, - String app, - String stream) { + 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.mediaServerItem = mediaServerItem; + this.event = event; + this.isFromPlatform = isFromPlatform; this.app = app; this.stream = stream; + this.mediaServerItem = mediaServerItem; } public AudioBroadcastCatch() { @@ -39,19 +46,24 @@ private String channelId; /** - * 浣跨敤鐨勬祦濯掍綋 + * 娴佸獟浣撲俊鎭� */ private MediaServerItem mediaServerItem; /** - * 寰呮帹閫佺粰璁惧鐨勬祦搴旂敤鍚� + * 鍏宠仈鐨勬祦APP */ private String app; /** - * 寰呮帹閫佺粰璁惧鐨勬祦ID + * 鍏宠仈鐨勬祦STREAM */ private String stream; + + /** + * 鏄惁鏄骇鑱旇闊冲枈璇� + */ + private boolean isFromPlatform; /** * 璇煶骞挎挱鐘舵�� @@ -62,6 +74,11 @@ * 璇锋眰淇℃伅 */ private SipTransactionInfo sipTransactionInfo; + + /** + * 璇锋眰缁撴灉鍥炶皟 + */ + private AudioBroadcastEvent event; public String getDeviceId() { @@ -123,4 +140,44 @@ public void setMediaServerItem(MediaServerItem mediaServerItem) { this.mediaServerItem = mediaServerItem; } + + 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 7564390..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 @@ -86,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/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java index 0425356..9d5425b 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,42 +18,56 @@ /** * 鍚戜笂绾у钩鍙版敞鍐� + * * @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 SN * @param fromTag FROM澶寸殑tag淇℃伅 @@ -59,32 +77,37 @@ /** * 鍚戜笂绾у洖澶岲eviceStatus鏌ヨ淇℃伅 + * * @param parentPlatform 骞冲彴淇℃伅 * @param sn * @param fromTag * @return */ - void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) throws SipException, InvalidArgumentException, ParseException; + void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) 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 +115,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 +145,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..b77a0a4 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,80 @@ return request; } + + public Request createInviteRequest(ParentPlatform platform, String channelId, String content, String viaTag, String fromTag, String ssrc, CallIdHeader callIdHeader) throws PeerUnavailableException, ParseException, InvalidArgumentException { + Request request = null; + //璇锋眰琛� + String platformHostAddress = platform.getServerIP() + ":" + platform.getServerPort(); + String localHostAddress = sipLayer.getLocalIp(platform.getDeviceIp())+":"+ platform.getDevicePort(); + SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, platformHostAddress); + //via + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); + 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(platform.getDeviceGBId(), 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, platformHostAddress); + 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(),localHostAddress)); + 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.isAsSender()?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.isAsSender()?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 3b6565a..4855114 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 @@ -591,12 +591,12 @@ return; } if (!mediaServerItem.isRtpEnable()) { - // 鍗曠鍙f殏涓嶆敮鎸佽闊冲璁� - logger.info("[璇煶瀵硅] 鍗曠鍙f殏涓嶆敮鎸佹鎿嶄綔"); + // 鍗曠鍙f殏涓嶆敮鎸佽闊冲枈璇� + logger.info("[璇煶鍠婅瘽] 鍗曠鍙f殏涓嶆敮鎸佹鎿嶄綔"); return; } - logger.info("[璇煶瀵硅] {} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.getPort()); + logger.info("[璇煶鍠婅瘽] {} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.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 4fef72d..9809a9f 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,23 +1,32 @@ 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.DynamicTask; +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; @@ -27,6 +36,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; @@ -61,6 +71,16 @@ @Autowired private SIPSender sipSender; + + @Autowired + private ZlmHttpHookSubscribe subscribe; + + @Autowired + private UserSetting userSetting; + + + @Autowired + private VideoStreamSessionManager streamSession; @Autowired private DynamicTask dynamicTask; @@ -335,6 +355,7 @@ Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceInfoXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader); sipSender.transmitRequest(parentPlatform.getDeviceIp(), request); } + /** * 鍚戜笂绾у洖澶岲eviceStatus鏌ヨ淇℃伅 @@ -702,4 +723,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("<Response>\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("</Response>\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(), ssrcInfo.getSsrc(), + callIdHeader); + 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 b00c83b..12bddb1 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 @@ -156,7 +156,6 @@ } } } - } } 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 c620354..c89279a 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 @@ -202,7 +202,7 @@ MediaServerItem mediaServerItem = null; StreamPushItem streamPushItem = null; - StreamProxyItem proxyByAppAndStream =null; + StreamProxyItem proxyByAppAndStream = null; // 涓嶆槸閫氶亾鍙兘鏄洿鎾祦 if (channel != null && gbStream == null) { // 閫氶亾瀛樺湪锛屽彂100锛孴RYING @@ -1018,7 +1018,7 @@ 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); @@ -1113,7 +1113,7 @@ } } 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..240f24f --- /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(null); + 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 cf5c34b..4b6bbbc 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 @@ -7,6 +7,7 @@ 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.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; @@ -53,9 +54,9 @@ @Override public void handForDevice(RequestEvent evt, Device device, Element rootElement) { - String channelId = getText(rootElement, "DeviceID"); SIPRequest request = (SIPRequest) evt.getRequest(); try { + String channelId = getText(rootElement, "DeviceID"); if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) { // 鍥炲410 responseAck((SIPRequest) evt.getRequest(), Response.GONE); 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 b5a9ee7..7feac17 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 eebb461..984a377 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 @@ -280,6 +280,9 @@ logger.info("[ZLM HOOK] 娴佹敞閿�, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); } + JSONObject ret = new JSONObject(); + ret.put("code", 0); + ret.put("msg", "success"); MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); JSONObject json = (JSONObject) JSON.toJSON(param); taskExecutor.execute(() -> { @@ -335,34 +338,34 @@ } }else if ("broadcast".equals(param.getApp())){ // 璇煶瀵硅鎺ㄦ祦 stream闇�瑕佹弧瓒虫牸寮廳eviceId_channelId - if (param.getStream().indexOf("_") > 0) { - String[] streamArray = param.getStream().split("_"); - if (streamArray.length == 2) { - String deviceId = streamArray[0]; - String channelId = streamArray[1]; - Device device = deviceService.getDevice(deviceId); - if (device != null) { - if (param.isRegist()) { - if (audioBroadcastManager.exit(deviceId, channelId)) { - playService.stopAudioBroadcast(deviceId, channelId); - } - // 寮�鍚闊冲璁查�氶亾 - try { - playService.audioBroadcastCmd(device, channelId, 60, mediaInfo, param.getApp(), param.getStream(), (msg)->{ - logger.info("[璇煶瀵硅] 閫氶亾寤虹珛鎴愬姛, device: {}, channel: {}", deviceId, channelId); - }); - } catch (InvalidArgumentException | ParseException | SipException e) { - logger.error("[鍛戒护鍙戦�佸け璐 璇煶瀵硅: {}", e.getMessage()); - } - }else { - // 娴佹敞閿� - playService.stopAudioBroadcast(deviceId, channelId); - } - } else{ - logger.info("[璇煶瀵硅] 鏈壘鍒拌澶囷細{}", deviceId); - } - } - } + if (param.getStream().indexOf("_") > 0) { + String[] streamArray = param.getStream().split("_"); + if (streamArray.length == 2) { + String deviceId = streamArray[0]; + String channelId = streamArray[1]; + Device device = deviceService.getDevice(deviceId); + if (device != null) { + if (param.isRegist()) { + if (audioBroadcastManager.exit(deviceId, channelId)) { + playService.stopAudioBroadcast(deviceId, channelId); + } + // 寮�鍚闊冲璁查�氶亾 + try { + 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()); + } + }else { + // 娴佹敞閿� + playService.stopAudioBroadcast(deviceId, channelId); + } + } else{ + logger.info("[璇煶瀵硅] 鏈壘鍒拌澶囷細{}", deviceId); + } + } + } }else if ("talk".equals(param.getApp())){ // 璇煶瀵硅鎺ㄦ祦 stream闇�瑕佹弧瓒虫牸寮廳eviceId_channelId if (param.getStream().indexOf("_") > 0) { 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 b382a3d..9a9dbe1 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 @@ -92,7 +92,7 @@ return result; } - public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port) { + public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port, Boolean onlyAuto) { int result = -1; // 鏌ヨ姝tp server 鏄惁宸茬粡瀛樺湪 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId); @@ -108,7 +108,7 @@ JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(mediaServerItem, param); if (jsonObject != null ) { if (jsonObject.getInteger("code") == 0) { - return createRTPServer(mediaServerItem, streamId, ssrc, port); + return createRTPServer(mediaServerItem, streamId, ssrc, port, onlyAuto); }else { logger.warn("[寮�鍚痳tpServer], 閲嶅惎RtpServer閿欒"); } @@ -131,6 +131,9 @@ param.put("port", port); } param.put("ssrc", ssrc); + if (onlyAuto != null) { + param.put("only_audio", onlyAuto?"1":"0"); + } JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param); logger.info(JSONObject.toJSONString(openRtpServerResultJson)); if (openRtpServerResultJson != null) { @@ -352,4 +355,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/IMediaServerService.java b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java index 1233455..bac3d50 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java @@ -47,7 +47,7 @@ SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback); - SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port); + SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port, Boolean onlyAuto); void closeRTPServer(MediaServerItem mediaServerItem, String streamId); 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 b87176f..3d6352b 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java @@ -12,7 +12,9 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import gov.nist.javax.sip.message.SIPResponse; +import org.springframework.web.context.request.async.DeferredResult; import javax.sip.InvalidArgumentException; import javax.sip.SipException; @@ -54,6 +56,11 @@ void zlmServerOnline(String mediaServerId); AudioBroadcastResult audioBroadcast(Device device, String channelId, Boolean broadcastMode); + + 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 audioBroadcastCmd(Device device, String channelId, int timeout, MediaServerItem mediaServerItem, String sourceApp, String sourceStream, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException; diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java index 522879a..226fa6f 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java @@ -1,16 +1,5 @@ package com.genersoft.iot.vmp.service.impl; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.genersoft.iot.vmp.media.zlm.ZLMRunner; -import com.genersoft.iot.vmp.service.IStreamProxyService; -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; @@ -39,8 +28,6 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import java.time.LocalDateTime; -import java.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -134,7 +121,8 @@ } @Override - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, boolean isPlayback, Integer port) { + public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, + boolean isPlayback, Integer port, Boolean onlyAuto) { if (mediaServerItem == null || mediaServerItem.getId() == null) { logger.info("[openRTPServer] 澶辫触, mediaServerItem == null || mediaServerItem.getId() == null"); return null; @@ -163,7 +151,7 @@ } int rtpServerPort; if (mediaServerItem.isRtpEnable()) { - rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port); + rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port, onlyAuto); } else { rtpServerPort = mediaServerItem.getRtpProxyPort(); } @@ -174,7 +162,7 @@ @Override public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback) { - return openRTPServer(mediaServerItem, streamId, ssrc, ssrcCheck, isPlayback, null); + return openRTPServer(mediaServerItem, streamId, ssrc, ssrcCheck, isPlayback, null, null); } @Override 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 1d48d54..1a788d2 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; @@ -310,4 +332,138 @@ } } } + + @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, null, ssrcCheck, false, null, true); + 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(), true); + + + } + } + }, 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 b89f173..7e85f0c 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 @@ -490,7 +490,7 @@ // 鍏抽棴rtp server mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); // 閲嶆柊寮�鍚痵src server - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort()); + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort(), false); } } @@ -731,7 +731,7 @@ // 鍏抽棴rtp server mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); // 閲嶆柊寮�鍚痵src server - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort()); + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), false); } } } @@ -966,16 +966,16 @@ } @Override - public void audioBroadcastCmd(Device device, String channelId, int timeout, MediaServerItem mediaServerItem, String sourceApp, String sourceStream, 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)) { @@ -986,7 +986,7 @@ if (streamReady) { logger.warn("璇煶骞挎挱宸茬粡寮�鍚細 {}", channelId); event.call("璇煶骞挎挱宸茬粡寮�鍚�"); - return; + return false; } else { stopAudioBroadcast(device.getDeviceId(), channelId); } @@ -1008,8 +1008,7 @@ // 鍙戦�侀�氱煡 cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> { // 鍙戦�佹垚鍔� - AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId, - AudioBroadcastCatchStatus.Ready, mediaServerItem, sourceApp, sourceStream); + AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId, mediaServerItem, app, stream, event, AudioBroadcastCatchStatus.Ready, isFromPlatform); audioBroadcastManager.update(audioBroadcastCatch); }, eventResultForError -> { // 鍙戦�佸け璐� @@ -1017,6 +1016,24 @@ 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; } 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 3eba74e..96031f8 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 @@ -250,10 +250,10 @@ @GetMapping("/broadcast/{deviceId}/{channelId}") @PostMapping("/broadcast/{deviceId}/{channelId}") public AudioBroadcastResult broadcastApi(@PathVariable String deviceId, @PathVariable String channelId, Integer timeout, Boolean broadcastMode) { - if (logger.isDebugEnabled()) { - logger.debug("璇煶骞挎挱API璋冪敤"); - } - Device device = storager.queryVideoDevice(deviceId); + if (logger.isDebugEnabled()) { + logger.debug("璇煶骞挎挱API璋冪敤"); + } + Device device = storager.queryVideoDevice(deviceId); if (device == null) { throw new ControllerException(ErrorCode.ERROR400.getCode(), "鏈壘鍒拌澶囷細 " + deviceId); } @@ -264,7 +264,6 @@ return playService.audioBroadcast(device, channelId, broadcastMode); } - @Operation(summary = "鍋滄璇煶骞挎挱") @Parameter(name = "deviceId", description = "璁惧Id", required = true) diff --git a/src/main/resources/all-application.yml b/src/main/resources/all-application.yml index c48c26e..4f7a8f6 100644 --- a/src/main/resources/all-application.yml +++ b/src/main/resources/all-application.yml @@ -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 # 鏄惁浣跨敤璁惧鏉ユ簮Ip浣滀负鍥炲IP锛� 涓嶈缃垯涓� false sip-use-source-ip-as-remote-address: false # 鏄惁寮�鍚痵ip鏃ュ織 diff --git a/web_src/src/components/dialog/devicePlayer.vue b/web_src/src/components/dialog/devicePlayer.vue index 0bc3335..61cf066 100644 --- a/web_src/src/components/dialog/devicePlayer.vue +++ b/web_src/src/components/dialog/devicePlayer.vue @@ -663,46 +663,46 @@ this.startBroadcast(streamInfo.rtc) } - }else { - this.$message({ - showClose: true, - message: res.data.msg, - type: "error", - }); - } - }); - }else if (this.broadcastStatus === 1) { - this.broadcastStatus = -1; - this.broadcastRtc.close() - } - }, - startBroadcast(url) { - // 鑾峰彇鎺ㄦ祦閴存潈Key - this.$axios({ - method: 'post', - url: '/api/user/userInfo', - }).then((res) => { - if (res.data.code !== 0) { - this.$message({ - showClose: true, - message: "鑾峰彇鎺ㄦ祦閴存潈Key澶辫触", - type: "error", - }); - this.broadcastStatus = -1; - } else { - let pushKey = res.data.data.pushKey; - // 鑾峰彇鎺ㄦ祦閴存潈KEY - url += "&sign=" + crypto.createHash('md5').update(pushKey, "utf8").digest('hex') - console.log("寮�濮嬭闊冲璁诧細 " + url) - this.broadcastRtc = new ZLMRTCClient.Endpoint({ - debug: true, // 鏄惁鎵撳嵃鏃ュ織 - zlmsdpUrl: url, //娴佸湴鍧� - simulecast: false, - useCamera: false, - audioEnable: true, - videoEnable: false, - recvOnly: false, - }) + }else { + this.$message({ + showClose: true, + message: res.data.msg, + type: "error", + }); + } + }); + }else if (this.broadcastStatus === 1) { + this.broadcastStatus = -1; + this.broadcastRtc.close() + } + }, + startBroadcast(url){ + // 鑾峰彇鎺ㄦ祦閴存潈Key + this.$axios({ + method: 'post', + url: '/api/user/userInfo', + }).then( (res)=> { + if (res.data.code !== 0) { + this.$message({ + showClose: true, + message: "鑾峰彇鎺ㄦ祦閴存潈Key澶辫触", + type: "error", + }); + this.broadcastStatus = -1; + }else { + let pushKey = res.data.data.pushKey; + // 鑾峰彇鎺ㄦ祦閴存潈KEY + url += "&sign=" + crypto.createHash('md5').update(pushKey, "utf8").digest('hex') + console.log("寮�濮嬭闊冲枈璇濓細 " + url) + this.broadcastRtc = new ZLMRTCClient.Endpoint({ + debug: true, // 鏄惁鎵撳嵃鏃ュ織 + zlmsdpUrl: url, //娴佸湴鍧� + simulecast: false, + useCamera: false, + audioEnable: true, + videoEnable: false, + recvOnly: false, + }) // webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,(e)=>{//鑾峰彇鍒颁簡杩滅娴侊紝鍙互鎾斁 // console.error('鎾斁鎴愬姛',e.streams) @@ -715,15 +715,15 @@ // // this.eventcallbacK("LOCAL STREAM", "鑾峰彇鍒颁簡鏈湴娴�") // }); - this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_NOT_SUPPORT, (e) => {// 鑾峰彇鍒颁簡鏈湴娴� - console.error('涓嶆敮鎸亀ebrtc', e) - this.$message({ - showClose: true, - message: '涓嶆敮鎸亀ebrtc, 鏃犳硶杩涜璇煶瀵硅', - type: 'error' - }); - this.broadcastStatus = -1; - }); + this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_NOT_SUPPORT,(e)=>{// 鑾峰彇鍒颁簡鏈湴娴� + console.error('涓嶆敮鎸亀ebrtc',e) + this.$message({ + showClose: true, + message: '涓嶆敮鎸亀ebrtc, 鏃犳硶杩涜璇煶鍠婅瘽', + type: 'error' + }); + this.broadcastStatus = -1; + }); this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, (e) => {// ICE 鍗忓晢鍑洪敊 console.error('ICE 鍗忓晢鍑洪敊') -- Gitblit v1.8.0