Commit 30ae9e929fad80f624ab632c53081db3d2dc9aec

Authored by 648540858
2 parents d295f3c5 512b0cc8

合并主线

Showing 128 changed files with 5910 additions and 2400 deletions
.github/ISSUE_TEMPLATE/--bug---.md renamed to .github/ISSUE_TEMPLATE/bug.md
1 --- 1 ---
2 name: "[ BUG ] " 2 name: "[ BUG ] "
3 -about: Create a report to help us improve  
4 -title: ''  
5 -labels: '' 3 +about: 关于wvp的bug,与zlm有关的建议直接在zlm的issue中提问
  4 +title: 'BUG'
  5 +labels: 'wvp的bug'
6 assignees: '' 6 assignees: ''
7 7
8 --- 8 ---
9 9
  10 +**环境信息:**
  11 +
  12 + - 1. 部署方式 wvp-pro docker / zlm(docker) + 编译wvp-pro/ wvp-prp + zlm都是编译部署/
  13 + - 2. 部署环境 windows / ubuntu/ centos ...
  14 + - 3. 端口开放情况
  15 + - 4. 是否是公网部署
  16 + - 5. 是否使用https
  17 + - 6. 方便的话提供下使用的设备品牌或平台
  18 + - 7. 你做过哪些尝试
  19 + - 8. 代码更新时间
  20 +
10 **描述错误** 21 **描述错误**
11 描述下您遇到的问题 22 描述下您遇到的问题
12 23
13 **如何复现** 24 **如何复现**
14 有明确复现步骤的问题会很容易被解决 25 有明确复现步骤的问题会很容易被解决
15 26
16 -**预期行为**  
17 -清晰简洁的描述您期望发生的事情 27 +**截图**
18 28
19 -**截图** 29 +**抓包文件**
  30 +
  31 +**日志**
  32 +```
  33 +日志内容放这里, 文件的话请直接上传
  34 +```
20 35
21 36
22 -**环境信息:**  
23 - - 1. 部署方式 wvp-pro docker / zlm(docker) + 编译wvp-pro/ wvp-prp + zlm都是编译部署/  
24 - - 2. 部署环境 windows / ubuntu/ centos ...  
25 - - 3. 端口开放情况  
26 - - 4. 是否是公网部署  
27 - - 5. 是否使用https  
28 - - 6. 方便的话提供下使用的设备品牌或平台  
29 - - 7. 你做过哪些尝试  
.github/ISSUE_TEMPLATE/-------.md renamed to .github/ISSUE_TEMPLATE/new.md
1 --- 1 ---
2 name: "[ 新功能 ]" 2 name: "[ 新功能 ]"
3 about: 新功能 3 about: 新功能
4 -title: '' 4 +title: '希望wVP实现的新功能,此功能应与你的具体业务无关'
5 labels: '' 5 labels: ''
6 assignees: '' 6 assignees: ''
7 7
8 --- 8 ---
9 9
  10 +**项目的详细需求**
  11 +
  12 +**这样的实现什么作用**
10 13
.github/ISSUE_TEMPLATE/solve.md 0 → 100644
  1 +---
  2 +name: "[ 技术咨询 ] "
  3 +about: 对于使用中遇到问题
  4 +title: '技术咨询'
  5 +labels: '技术咨询'
  6 +assignees: ''
  7 +
  8 +---
  9 +
  10 +**环境信息:**
  11 +
  12 + - 1. 部署方式 wvp-pro docker / zlm(docker) + 编译wvp-pro/ wvp-prp + zlm都是编译部署/
  13 + - 2. 部署环境 windows / ubuntu/ centos ...
  14 + - 3. 端口开放情况
  15 + - 4. 是否是公网部署
  16 + - 5. 是否使用https
  17 + - 6. 方便的话提供下使用的设备品牌或平台
  18 + - 7. 你做过哪些尝试
  19 + - 8. 代码更新时间
  20 +
  21 +
  22 +**内容描述:**
  23 +
  24 +**截图**
  25 +
  26 +**抓包文件**
  27 +
  28 +**日志**
  29 +```
  30 +日志内容放这里, 文件的话请直接上传
  31 +```
README.md
@@ -15,17 +15,21 @@ WEB VIDEO PLATFORM銝銝芸鈭B28181-2016蝞勗 @@ -15,17 +15,21 @@ WEB VIDEO PLATFORM銝銝芸鈭B28181-2016蝞勗
15 垢憿菟鈭Kyle MediaServerUI [https://gitee.com/kkkkk5G/MediaServerUI](https://gitee.com/kkkkk5G/MediaServerUI) 餈耨. 15 垢憿菟鈭Kyle MediaServerUI [https://gitee.com/kkkkk5G/MediaServerUI](https://gitee.com/kkkkk5G/MediaServerUI) 餈耨.
16 16
17 # 摨嚗 17 # 摨嚗
18 -辣仍閫  
19 -像VR蝑挽憭 18 +辣仍閫
  19 +挽憭(像VR蝑)霈曉
  20 +(onvif, rtsp, rtmp嚗霈曉)霈曉嚗
20 漣像蝥扯楊蝵 21 漣像蝥扯楊蝵
21 -tsp/rtmp蝑蓮像  
22 -tsp/rtmp蝑瘚蓮像 22 +楊蝵撟喳鈭
23 23
24 -# 憿寧  
25 -銝芣蔭,蝙,靘蹂輕28181縑隞斤頂蝏, 靘皞獢ZLMediaKit, 摰銝銝芸GB28181撟喳.  
26 24
27 -# 蝵脫﹝  
28 -[doc.wvp-pro.cn](https://doc.wvp-pro.cn) 25 +# ﹝
  26 +wvp雿輻﹝ [https://doc.wvp-pro.cn](https://doc.wvp-pro.cn)
  27 +ZLM雿輻﹝ [https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)
  28 +> wvp﹝gitee嚗霂瑕活
  29 +
  30 +# 蝷曄黎
  31 +[![蝷曄黎](doc/_media/shequ.png "shequ")](https://t.zsxq.com/0d8VAD3Dm)
  32 +> 韐寞銝箔憟賜嚗撖嫣憭抒銝予隞亦縑凝靽∪嚗之摰嗅蝢扎銝予說隞亦甈橘之摰嗡閬▽憳予銋銝隞乓
29 33
30 # gitee郊隞 34 # gitee郊隞
31 https://gitee.com/pan648540858/wvp-GB28181-pro.git 35 https://gitee.com/pan648540858/wvp-GB28181-pro.git
@@ -100,23 +104,17 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git @@ -100,23 +104,17 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
100 - [X] 鈭垢敶瘚/隞/隞亙鈭垢嚗蝸 104 - [X] 鈭垢敶瘚/隞/隞亙鈭垢嚗蝸
101 - [X] 銵arar 105 - [X] 銵arar
102 - [X] 楊窈瘙垢氖蝵 106 - [X] 楊窈瘙垢氖蝵
103 -  
104 -  
105 -# 憸圾  
106 -暻餌鈭挽憭摰寞改隞仿閬之挽憭瘚挽憭偌撟單隞仿憸  
107 -1. ﹝蝵粉隞亙葬雿憸  
108 -2. 揣issues嚗之  
109 -3. Q蝢歹901799015嚗之敹撈嚗撣歇蝏粉鈭iki揣鈭ssues  
110 -4. 雿隞亥窈雿蛹雿圾蝑晶  
111 -5. 雿隞交憸挽憭隞交摰寞摰寡挽憭圾憸  
112 -  
113 -# 雿輻撣桀  
114 -QQ蝢: 901799015, ZLM雿輻﹝[https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)  
115 -QQ蝘縑銝銝, 蝎曉.甈Z之摰嗅蝢日悄霈.閫★撖嫣葬嚗洽餈tar漱pr  
116 107
117 # 悅 108 # 悅
118 憿寧誨蝙摰賣IT悅嚗靽縑銝隞亥摨鈭★ 雿憿寧銋蝣蝙鈭鈭隞皞誨銝窈銵隞嚗 鈭蝙憿寧漣熒噩蛹銝璁憿寧嚗窈銵 雿輻憿寧隞嚗砲悅銝剖銵冽憿寧靘洵銝摨悅 109 憿寧誨蝙摰賣IT悅嚗靽縑銝隞亥摨鈭★ 雿憿寧銋蝣蝙鈭鈭隞皞誨銝窈銵隞嚗 鈭蝙憿寧漣熒噩蛹銝璁憿寧嚗窈銵 雿輻憿寧隞嚗砲悅銝剖銵冽憿寧靘洵銝摨悅
119 110
  111 +#
  112 +
  113 +[霂(https://t.zsxq.com/0d8VAD3Dm)銝”嚗
  114 +- [雿輻蝟餃嚗VP-PRO銋(https://t.zsxq.com/0dLguVoSp)
  115 +
  116 +窈隞嗅648540858@qq.com
  117 +
120 # 靚 118 # 靚
121 陝雿憭(https://github.com/xia-chu) 皞獢,撟嗅撘葉蝏葬 119 陝雿憭(https://github.com/xia-chu) 皞獢,撟嗅撘葉蝏葬
122 陝雿dexter langhuihui](https://github.com/langhuihui) 撘皞末EB 120 陝雿dexter langhuihui](https://github.com/langhuihui) 撘皞末EB
@@ -128,7 +126,6 @@ QQ蝘縑銝銝, 蝎曉.甈Z之摰嗅蝢日悄霈.閫★撖嫣 @@ -128,7 +126,6 @@ QQ蝘縑銝銝, 蝎曉.甈Z之摰嗅蝢日悄霈.閫★撖嫣
128 [ydpd](https://github.com/ydpd) [szy833](https://github.com/szy833) [ydwxb](https://github.com/ydwxb) [Albertzhu666](https://github.com/Albertzhu666) 126 [ydpd](https://github.com/ydpd) [szy833](https://github.com/szy833) [ydwxb](https://github.com/ydwxb) [Albertzhu666](https://github.com/Albertzhu666)
129 [mk1990](https://github.com/mk1990) [SaltFish001](https://github.com/SaltFish001) 127 [mk1990](https://github.com/mk1990) [SaltFish001](https://github.com/SaltFish001)
130 128
131 -ps: 葵摰鈭之雿穿洽餈之雿祈頂溶  
132 129
133 ffmpeg -re -i 123.mp3 -acodec pcm_alaw -ar 8000 -ac 1 -f rtsp rtsp://192.168.1.3:30554/broadcast/34020000001320000101_34020000001310000001 130 ffmpeg -re -i 123.mp3 -acodec pcm_alaw -ar 8000 -ac 1 -f rtsp rtsp://192.168.1.3:30554/broadcast/34020000001320000101_34020000001310000001
134 131
doc/README.md
@@ -14,6 +14,10 @@ @@ -14,6 +14,10 @@
14 - 完全开源,且使用MIT许可协议。保留版权的情况下可以用于商业项目。 14 - 完全开源,且使用MIT许可协议。保留版权的情况下可以用于商业项目。
15 - 支持多流媒体节点负载均衡。 15 - 支持多流媒体节点负载均衡。
16 16
  17 +# 社群
  18 +[![社群](_media/shequ.png "shequ")](https://t.zsxq.com/0d8VAD3Dm)
  19 +> 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。加入三天内不满意可以直接退款,大家不需要有顾虑,来白嫖三天也不是不可以。
  20 +
17 # 我们实现了哪些国标功能 21 # 我们实现了哪些国标功能
18 **作为上级平台** 22 **作为上级平台**
19 - [X] 注册 23 - [X] 注册
doc/_content/ability/_media/img_16.png

41.5 KB | W: | H:

112 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
doc/_content/qa/bug.md
@@ -2,18 +2,11 @@ @@ -2,18 +2,11 @@
2 # 反馈bug 2 # 反馈bug
3 代码是在不断的完善的,不断修改会修复旧的问题也有可能引入新的问题,所以遇到BUG是很正常的一件事。所以遇到问题不要烦燥,咱们就事论事就好了。 3 代码是在不断的完善的,不断修改会修复旧的问题也有可能引入新的问题,所以遇到BUG是很正常的一件事。所以遇到问题不要烦燥,咱们就事论事就好了。
4 ## 如何反馈 4 ## 如何反馈
5 -1. 更新代码,很可能你遇到问题别人已经更早的遇到了,或者是作者自己发现了,已经解决了,所以你可以更新代码再次进行测试;  
6 -2. 可以在github提ISSUE,我几乎每天都会去看issue,你的问题我会尽快给予答复;  
7 -3. 你可以来我的QQ群里,询问群友看看是否遇到了同样的问题;  
8 -4. 你可以私聊我的QQ,如果我有时间我会给你答复,但是除非你有明确的复现步骤或者修复方案,否则你可能等不到我的答复。  
9 -  
10 -## 如何快速解决BUG  
11 -目前解决BUG有三种方式:  
12 -1. 作者验证以及修复;  
13 -2. 热心开发者提来的PR;  
14 -3. 使用运维手段屏蔽BUG的影响。  
15 -  
16 -- 对于第一种:详细的复现步骤,完整的抓包文件,有条理的错误分析都可以帮助作者复现问题,进而解决问题。解决问题往往不是最难的,复现才是。  
17 -- 对于第二种:如果你是开发者,你已经发现了造成BUG的原因以及知道如何正确的修复,那么我很希望你PR,SRS的大佬经常说的,开源不是一个人的事。所以你的参与就是最大的鼓励。  
18 -- 对于第三种:如果你有一个有经验的运维伙伴,那么部分问题是可以通过运维的手段暂时屏蔽的,在等待修复的这段时间了以保证项目的运行。 5 +1. 在知识星球提问。
  6 +2. 更新代码,很可能你遇到问题别人已经更早的遇到了,或者是作者自己发现了,已经解决了,所以你可以更新代码再次进行测试;
  7 +3. 可以在github提ISSUE,我几乎每天都会去看issue,你的问题我会尽快给予答复;
  8 +> 有偿支持可以给我发邮件, 648540858@qq.com
19 9
  10 +## 社群
  11 +[![社群](../../_media/shequ.png "shequ")](https://t.zsxq.com/0d8VAD3Dm)
  12 +> 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。加入三天内不满意可以直接退款,大家不需要有顾虑,来白嫖三天也不是不可以。
20 \ No newline at end of file 13 \ No newline at end of file
doc/_media/shequ.png 0 → 100644

35.3 KB

src/main/java/com/genersoft/iot/vmp/common/CommonCallback.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +public interface CommonCallback<T>{
  4 + public void run(T t);
  5 +}
src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  4 +
  5 +/**
  6 + * 记录每次发送invite消息的状态
  7 + */
  8 +public class InviteInfo {
  9 +
  10 + private String deviceId;
  11 +
  12 + private String channelId;
  13 +
  14 + private String stream;
  15 +
  16 + private SSRCInfo ssrcInfo;
  17 +
  18 + private String receiveIp;
  19 +
  20 + private Integer receivePort;
  21 +
  22 + private String streamMode;
  23 +
  24 + private InviteSessionType type;
  25 +
  26 + private InviteSessionStatus status;
  27 +
  28 + private StreamInfo streamInfo;
  29 +
  30 +
  31 + public static InviteInfo getinviteInfo(String deviceId, String channelId, String stream, SSRCInfo ssrcInfo,
  32 + String receiveIp, Integer receivePort, String streamMode,
  33 + InviteSessionType type, InviteSessionStatus status) {
  34 + InviteInfo inviteInfo = new InviteInfo();
  35 + inviteInfo.setDeviceId(deviceId);
  36 + inviteInfo.setChannelId(channelId);
  37 + inviteInfo.setStream(stream);
  38 + inviteInfo.setSsrcInfo(ssrcInfo);
  39 + inviteInfo.setReceiveIp(receiveIp);
  40 + inviteInfo.setReceivePort(receivePort);
  41 + inviteInfo.setStreamMode(streamMode);
  42 + inviteInfo.setType(type);
  43 + inviteInfo.setStatus(status);
  44 + return inviteInfo;
  45 + }
  46 +
  47 + public String getDeviceId() {
  48 + return deviceId;
  49 + }
  50 +
  51 + public void setDeviceId(String deviceId) {
  52 + this.deviceId = deviceId;
  53 + }
  54 +
  55 + public String getChannelId() {
  56 + return channelId;
  57 + }
  58 +
  59 + public void setChannelId(String channelId) {
  60 + this.channelId = channelId;
  61 + }
  62 +
  63 + public InviteSessionType getType() {
  64 + return type;
  65 + }
  66 +
  67 + public void setType(InviteSessionType type) {
  68 + this.type = type;
  69 + }
  70 +
  71 + public InviteSessionStatus getStatus() {
  72 + return status;
  73 + }
  74 +
  75 + public void setStatus(InviteSessionStatus status) {
  76 + this.status = status;
  77 + }
  78 +
  79 + public StreamInfo getStreamInfo() {
  80 + return streamInfo;
  81 + }
  82 +
  83 + public void setStreamInfo(StreamInfo streamInfo) {
  84 + this.streamInfo = streamInfo;
  85 + }
  86 +
  87 + public String getStream() {
  88 + return stream;
  89 + }
  90 +
  91 + public void setStream(String stream) {
  92 + this.stream = stream;
  93 + }
  94 +
  95 + public SSRCInfo getSsrcInfo() {
  96 + return ssrcInfo;
  97 + }
  98 +
  99 + public void setSsrcInfo(SSRCInfo ssrcInfo) {
  100 + this.ssrcInfo = ssrcInfo;
  101 + }
  102 +
  103 + public String getReceiveIp() {
  104 + return receiveIp;
  105 + }
  106 +
  107 + public void setReceiveIp(String receiveIp) {
  108 + this.receiveIp = receiveIp;
  109 + }
  110 +
  111 + public Integer getReceivePort() {
  112 + return receivePort;
  113 + }
  114 +
  115 + public void setReceivePort(Integer receivePort) {
  116 + this.receivePort = receivePort;
  117 + }
  118 +
  119 + public String getStreamMode() {
  120 + return streamMode;
  121 + }
  122 +
  123 + public void setStreamMode(String streamMode) {
  124 + this.streamMode = streamMode;
  125 + }
  126 +}
src/main/java/com/genersoft/iot/vmp/common/InviteSessionStatus.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +/**
  4 + * 标识invite消息发出后的各个状态,
  5 + * 收到ok钱停止invite发送cancel,
  6 + * 收到200ok后发送BYE停止invite
  7 + */
  8 +public enum InviteSessionStatus {
  9 + ready,
  10 + ok,
  11 +}
src/main/java/com/genersoft/iot/vmp/common/InviteSessionType.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +public enum InviteSessionType {
  4 + PLAY,
  5 + PLAYBACK,
  6 + DOWNLOAD,
  7 + BROADCAST,
  8 + TALK
  9 +}
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -16,8 +16,6 @@ public class VideoManagerConstants { @@ -16,8 +16,6 @@ public class VideoManagerConstants {
16 16
17 public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_"; 17 public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_";
18 18
19 - public static final String MEDIA_STREAM_PREFIX = "VMP_MEDIA_STREAM";  
20 -  
21 public static final String DEVICE_PREFIX = "VMP_DEVICE_"; 19 public static final String DEVICE_PREFIX = "VMP_DEVICE_";
22 20
23 // 设备同步完成 21 // 设备同步完成
@@ -28,9 +26,10 @@ public class VideoManagerConstants { @@ -28,9 +26,10 @@ public class VideoManagerConstants {
28 public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_"; 26 public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_";
29 27
30 // TODO 此处多了一个_,暂不修改 28 // TODO 此处多了一个_,暂不修改
31 - public static final String PLAYER_PREFIX = "VMP_PLAYER_";  
32 - public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_";  
33 - public static final String DOWNLOAD_PREFIX = "VMP_DOWNLOAD_"; 29 + public static final String INVITE_PREFIX = "VMP_INVITE";
  30 + public static final String PLAYER_PREFIX = "VMP_INVITE_PLAY_";
  31 + public static final String PLAY_BLACK_PREFIX = "VMP_INVITE_PLAYBACK_";
  32 + public static final String DOWNLOAD_PREFIX = "VMP_INVITE_DOWNLOAD_";
34 33
35 public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_"; 34 public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_";
36 35
@@ -123,6 +122,7 @@ public class VideoManagerConstants { @@ -123,6 +122,7 @@ public class VideoManagerConstants {
123 */ 122 */
124 public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm"; 123 public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm";
125 124
  125 +
126 /** 126 /**
127 * 报警通知的发送 (收到redis发出的通知,转发给其他平台) 127 * 报警通知的发送 (收到redis发出的通知,转发给其他平台)
128 */ 128 */
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
@@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.conf; @@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.conf;
2 2
3 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 3 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
4 import com.genersoft.iot.vmp.service.IMediaServerService; 4 import com.genersoft.iot.vmp.service.IMediaServerService;
5 -import org.apache.catalina.connector.ClientAbortException;  
6 import org.apache.http.HttpHost; 5 import org.apache.http.HttpHost;
7 import org.apache.http.HttpRequest; 6 import org.apache.http.HttpRequest;
8 import org.apache.http.HttpResponse; 7 import org.apache.http.HttpResponse;
@@ -194,11 +193,11 @@ public class ProxyServletConfig { @@ -194,11 +193,11 @@ public class ProxyServletConfig {
194 } catch (IOException ioException) { 193 } catch (IOException ioException) {
195 if (ioException instanceof ConnectException) { 194 if (ioException instanceof ConnectException) {
196 logger.error("录像服务 连接失败"); 195 logger.error("录像服务 连接失败");
197 - }else if (ioException instanceof ClientAbortException) {  
198 - /**  
199 - * TODO 使用这个代理库实现代理在遇到代理视频文件时,如果是206结果,会遇到报错蛋市目前功能正常,  
200 - * TODO 暂时去除异常处理。后续使用其他代理框架修改测试  
201 - */ 196 +// }else if (ioException instanceof ClientAbortException) {
  197 +// /**
  198 +// * TODO 使用这个代理库实现代理在遇到代理视频文件时,如果是206结果,会遇到报错蛋市目前功能正常,
  199 +// * TODO 暂时去除异常处理。后续使用其他代理框架修改测试
  200 +// */
202 201
203 }else { 202 }else {
204 logger.error("录像服务 代理失败: ", e); 203 logger.error("录像服务 代理失败: ", e);
src/main/java/com/genersoft/iot/vmp/conf/ScheduleConfig.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf;
  2 +
  3 +import org.apache.commons.lang3.concurrent.BasicThreadFactory;
  4 +import org.springframework.context.annotation.Configuration;
  5 +import org.springframework.scheduling.annotation.SchedulingConfigurer;
  6 +import org.springframework.scheduling.config.ScheduledTaskRegistrar;
  7 +
  8 +import java.util.concurrent.ScheduledThreadPoolExecutor;
  9 +import java.util.concurrent.ThreadPoolExecutor;
  10 +
  11 +/**
  12 + * "@Scheduled"是Spring框架提供的一种定时任务执行机制,默认情况下它是单线程的,在同时执行多个定时任务时可能会出现阻塞和性能问题。
  13 + * 为了解决这种单线程瓶颈问题,可以将定时任务的执行机制改为支持多线程
  14 + */
  15 +@Configuration
  16 +public class ScheduleConfig implements SchedulingConfigurer {
  17 +
  18 + public static final int cpuNum = Runtime.getRuntime().availableProcessors();
  19 +
  20 + private static final int corePoolSize = cpuNum;
  21 +
  22 + private static final String threadNamePrefix = "scheduled-task-pool-%d";
  23 +
  24 + @Override
  25 + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
  26 + taskRegistrar.setScheduler(new ScheduledThreadPoolExecutor(corePoolSize,
  27 + new BasicThreadFactory.Builder().namingPattern(threadNamePrefix).daemon(true).build(),
  28 + new ThreadPoolExecutor.CallerRunsPolicy()));
  29 + }
  30 +}
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
@@ -48,10 +48,13 @@ public class SipPlatformRunner implements CommandLineRunner { @@ -48,10 +48,13 @@ public class SipPlatformRunner implements CommandLineRunner {
48 parentPlatformCatch.setParentPlatform(parentPlatform); 48 parentPlatformCatch.setParentPlatform(parentPlatform);
49 parentPlatformCatch.setId(parentPlatform.getServerGBId()); 49 parentPlatformCatch.setId(parentPlatform.getServerGBId());
50 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); 50 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
51 - // 取消订阅  
52 - sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{  
53 - platformService.login(parentPlatform);  
54 - }); 51 + if (parentPlatformCatchOld != null) {
  52 + // 取消订阅
  53 + sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{
  54 + platformService.login(parentPlatform);
  55 + });
  56 + }
  57 +
55 // 设置所有平台离线 58 // 设置所有平台离线
56 platformService.offline(parentPlatform, true); 59 platformService.offline(parentPlatform, true);
57 } 60 }
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -54,6 +54,9 @@ public class UserSetting { @@ -54,6 +54,9 @@ public class UserSetting {
54 54
55 private Boolean refuseChannelStatusChannelFormNotify = Boolean.FALSE; 55 private Boolean refuseChannelStatusChannelFormNotify = Boolean.FALSE;
56 56
  57 + private Boolean deviceStatusNotify = Boolean.FALSE;
  58 + private Boolean useCustomSsrcForParentInvite = Boolean.TRUE;
  59 +
57 private String serverId = "000000"; 60 private String serverId = "000000";
58 61
59 private String recordPath = null; 62 private String recordPath = null;
@@ -66,6 +69,8 @@ public class UserSetting { @@ -66,6 +69,8 @@ public class UserSetting {
66 69
67 private List<String> allowedOrigins = new ArrayList<>(); 70 private List<String> allowedOrigins = new ArrayList<>();
68 71
  72 + private int maxNotifyCountQueue = 10000;
  73 +
69 public Boolean getSavePositionHistory() { 74 public Boolean getSavePositionHistory() {
70 return savePositionHistory; 75 return savePositionHistory;
71 } 76 }
@@ -277,4 +282,28 @@ public class UserSetting { @@ -277,4 +282,28 @@ public class UserSetting {
277 public void setRecordPath(String recordPath) { 282 public void setRecordPath(String recordPath) {
278 this.recordPath = recordPath; 283 this.recordPath = recordPath;
279 } 284 }
  285 +
  286 + public int getMaxNotifyCountQueue() {
  287 + return maxNotifyCountQueue;
  288 + }
  289 +
  290 + public void setMaxNotifyCountQueue(int maxNotifyCountQueue) {
  291 + this.maxNotifyCountQueue = maxNotifyCountQueue;
  292 + }
  293 +
  294 + public Boolean getDeviceStatusNotify() {
  295 + return deviceStatusNotify;
  296 + }
  297 +
  298 + public void setDeviceStatusNotify(Boolean deviceStatusNotify) {
  299 + this.deviceStatusNotify = deviceStatusNotify;
  300 + }
  301 +
  302 + public Boolean getUseCustomSsrcForParentInvite() {
  303 + return useCustomSsrcForParentInvite;
  304 + }
  305 +
  306 + public void setUseCustomSsrcForParentInvite(Boolean useCustomSsrcForParentInvite) {
  307 + this.useCustomSsrcForParentInvite = useCustomSsrcForParentInvite;
  308 + }
280 } 309 }
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java
1 -package com.genersoft.iot.vmp.conf.redis;  
2 -  
3 -  
4 -import com.genersoft.iot.vmp.common.VideoManagerConstants;  
5 -import com.genersoft.iot.vmp.service.redisMsg.*;  
6 -import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;  
7 -import org.springframework.beans.factory.annotation.Autowired;  
8 -import org.springframework.cache.annotation.CachingConfigurerSupport;  
9 -import com.alibaba.fastjson2.support.spring.data.redis.GenericFastJsonRedisSerializer;  
10 -import org.springframework.context.annotation.Bean;  
11 -import org.springframework.context.annotation.Configuration;  
12 -import org.springframework.core.annotation.Order;  
13 -import org.springframework.data.redis.connection.RedisConnectionFactory;  
14 -import org.springframework.data.redis.core.RedisTemplate;  
15 -import org.springframework.data.redis.serializer.StringRedisSerializer;  
16 -  
17 -  
18 -/**  
19 - * Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置  
20 - * swwheihei  
21 - * 2019年5月30日 上午10:58:25  
22 - *  
23 - */  
24 -@Configuration  
25 -@Order(value=1)  
26 -public class RedisConfig {  
27 -  
28 -  
29 - @Bean  
30 - public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {  
31 -  
32 - RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();  
33 - // 使用fastJson序列化  
34 - GenericFastJsonRedisSerializer fastJsonRedisSerializer = new GenericFastJsonRedisSerializer();  
35 - // value值的序列化采用fastJsonRedisSerializer  
36 - redisTemplate.setValueSerializer(fastJsonRedisSerializer);  
37 - redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);  
38 -  
39 - // key的序列化采用StringRedisSerializer  
40 - redisTemplate.setKeySerializer(new StringRedisSerializer());  
41 - redisTemplate.setHashKeySerializer(new StringRedisSerializer());  
42 - redisTemplate.setConnectionFactory(redisConnectionFactory);  
43 - return redisTemplate;  
44 - }  
45 -}  
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisTemplateConfig.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf.redis;
  2 +
  3 +import com.alibaba.fastjson2.support.spring.data.redis.GenericFastJsonRedisSerializer;
  4 +import org.springframework.context.annotation.Bean;
  5 +import org.springframework.context.annotation.Configuration;
  6 +import org.springframework.data.redis.connection.RedisConnectionFactory;
  7 +import org.springframework.data.redis.core.RedisTemplate;
  8 +import org.springframework.data.redis.serializer.StringRedisSerializer;
  9 +
  10 +@Configuration
  11 +public class RedisTemplateConfig {
  12 +
  13 + @Bean
  14 + public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
  15 + RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
  16 + // 使用fastJson序列化
  17 + GenericFastJsonRedisSerializer fastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
  18 + // value值的序列化采用fastJsonRedisSerializer
  19 + redisTemplate.setValueSerializer(fastJsonRedisSerializer);
  20 + redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
  21 +
  22 + // key的序列化采用StringRedisSerializer
  23 + redisTemplate.setKeySerializer(new StringRedisSerializer());
  24 + redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  25 + redisTemplate.setConnectionFactory(redisConnectionFactory);
  26 + return redisTemplate;
  27 + }
  28 +}
src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java
@@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.conf.security; @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.conf.security;
2 2
3 import com.genersoft.iot.vmp.conf.UserSetting; 3 import com.genersoft.iot.vmp.conf.UserSetting;
4 import com.genersoft.iot.vmp.conf.security.dto.JwtUser; 4 import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
  5 +import com.genersoft.iot.vmp.storager.dao.dto.Role;
  6 +import com.genersoft.iot.vmp.storager.dao.dto.User;
5 import org.apache.commons.lang3.StringUtils; 7 import org.apache.commons.lang3.StringUtils;
6 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 9 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -38,7 +40,6 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @@ -38,7 +40,6 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
38 return; 40 return;
39 } 41 }
40 if (!userSetting.isInterfaceAuthentication()) { 42 if (!userSetting.isInterfaceAuthentication()) {
41 - // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录  
42 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>() ); 43 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>() );
43 SecurityContextHolder.getContext().setAuthentication(token); 44 SecurityContextHolder.getContext().setAuthentication(token);
44 chain.doFilter(request, response); 45 chain.doFilter(request, response);
@@ -76,7 +77,13 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @@ -76,7 +77,13 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
76 } 77 }
77 78
78 // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录 79 // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录
79 - UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, jwtUser.getPassword(), new ArrayList<>() ); 80 + User user = new User();
  81 + user.setUsername(jwtUser.getUserName());
  82 + user.setPassword(jwtUser.getPassword());
  83 + Role role = new Role();
  84 + role.setId(jwtUser.getRoleId());
  85 + user.setRole(role);
  86 + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, jwtUser.getPassword(), new ArrayList<>() );
80 SecurityContextHolder.getContext().setAuthentication(token); 87 SecurityContextHolder.getContext().setAuthentication(token);
81 chain.doFilter(request, response); 88 chain.doFilter(request, response);
82 } 89 }
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
@@ -37,7 +37,7 @@ public class JwtUtils { @@ -37,7 +37,7 @@ public class JwtUtils {
37 */ 37 */
38 public static final long expirationTime = 30; 38 public static final long expirationTime = 30;
39 39
40 - public static String createToken(String username, String password) { 40 + public static String createToken(String username, String password, Integer roleId) {
41 try { 41 try {
42 /** 42 /**
43 * “iss” (issuer) 发行人 43 * “iss” (issuer) 发行人
@@ -64,6 +64,7 @@ public class JwtUtils { @@ -64,6 +64,7 @@ public class JwtUtils {
64 //添加自定义参数,必须是字符串类型 64 //添加自定义参数,必须是字符串类型
65 claims.setClaim("username", username); 65 claims.setClaim("username", username);
66 claims.setClaim("password", password); 66 claims.setClaim("password", password);
  67 + claims.setClaim("roleId", roleId);
67 68
68 //jws 69 //jws
69 JsonWebSignature jws = new JsonWebSignature(); 70 JsonWebSignature jws = new JsonWebSignature();
@@ -118,8 +119,10 @@ public class JwtUtils { @@ -118,8 +119,10 @@ public class JwtUtils {
118 119
119 String username = (String) claims.getClaimValue("username"); 120 String username = (String) claims.getClaimValue("username");
120 String password = (String) claims.getClaimValue("password"); 121 String password = (String) claims.getClaimValue("password");
  122 + Long roleId = (Long) claims.getClaimValue("roleId");
121 jwtUser.setUserName(username); 123 jwtUser.setUserName(username);
122 jwtUser.setPassword(password); 124 jwtUser.setPassword(password);
  125 + jwtUser.setRoleId(roleId.intValue());
123 126
124 return jwtUser; 127 return jwtUser;
125 } catch (InvalidJwtException e) { 128 } catch (InvalidJwtException e) {
src/main/java/com/genersoft/iot/vmp/conf/security/LoginFailureHandler.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.conf.security;  
2 -  
3 -import com.fasterxml.jackson.databind.ObjectMapper;  
4 -import org.slf4j.Logger;  
5 -import org.slf4j.LoggerFactory;  
6 -import org.springframework.beans.factory.annotation.Autowired;  
7 -import org.springframework.security.authentication.*;  
8 -import org.springframework.security.core.AuthenticationException;  
9 -import org.springframework.security.web.authentication.AuthenticationFailureHandler;  
10 -import org.springframework.stereotype.Component;  
11 -  
12 -import javax.servlet.ServletException;  
13 -import javax.servlet.http.HttpServletRequest;  
14 -import javax.servlet.http.HttpServletResponse;  
15 -import java.io.IOException;  
16 -import java.util.HashMap;  
17 -import java.util.Map;  
18 -  
19 -@Component  
20 -public class LoginFailureHandler implements AuthenticationFailureHandler {  
21 -  
22 - private final static Logger logger = LoggerFactory.getLogger(LoginFailureHandler.class);  
23 -  
24 - @Autowired  
25 - private ObjectMapper objectMapper;  
26 -  
27 - @Override  
28 - public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {  
29 -  
30 - String username = request.getParameter("username");  
31 - if (e instanceof AccountExpiredException) {  
32 - // 账号过期  
33 - logger.info("[登录失败] - 用户[{}]账号过期", username);  
34 -  
35 - } else if (e instanceof BadCredentialsException) {  
36 - // 密码错误  
37 - logger.info("[登录失败] - 用户[{}]密码/SIP服务器ID 错误", username);  
38 -  
39 - } else if (e instanceof CredentialsExpiredException) {  
40 - // 密码过期  
41 - logger.info("[登录失败] - 用户[{}]密码过期", username);  
42 -  
43 - } else if (e instanceof DisabledException) {  
44 - // 用户被禁用  
45 - logger.info("[登录失败] - 用户[{}]被禁用", username);  
46 -  
47 - } else if (e instanceof LockedException) {  
48 - // 用户被锁定  
49 - logger.info("[登录失败] - 用户[{}]被锁定", username);  
50 -  
51 - } else if (e instanceof InternalAuthenticationServiceException) {  
52 - // 内部错误  
53 - logger.error(String.format("[登录失败] - [%s]内部错误", username), e);  
54 -  
55 - } else {  
56 - // 其他错误  
57 - logger.error(String.format("[登录失败] - [%s]其他错误", username), e);  
58 - }  
59 - Map<String, Object> map = new HashMap<>();  
60 - map.put("code","0");  
61 - map.put("msg","登录失败");  
62 - response.setContentType("application/json;charset=UTF-8");  
63 - response.getWriter().write(objectMapper.writeValueAsString(map));  
64 - }  
65 -}  
src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.conf.security;  
2 -  
3 -import org.slf4j.Logger;  
4 -import org.slf4j.LoggerFactory;  
5 -import org.springframework.security.core.Authentication;  
6 -import org.springframework.security.web.authentication.AuthenticationSuccessHandler;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.servlet.ServletException;  
10 -import javax.servlet.http.HttpServletRequest;  
11 -import javax.servlet.http.HttpServletResponse;  
12 -import java.io.IOException;  
13 -  
14 -/**  
15 - * @author lin  
16 - */  
17 -@Component  
18 -public class LoginSuccessHandler implements AuthenticationSuccessHandler {  
19 -  
20 - private final static Logger logger = LoggerFactory.getLogger(LoginSuccessHandler.class);  
21 -  
22 - @Override  
23 - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {  
24 -// String username = request.getParameter("username");  
25 -// httpServletResponse.setContentType("application/json;charset=UTF-8");  
26 -// // 生成JWT,并放置到请求头中  
27 -// String jwt = JwtUtils.createToken(authentication.getName(), );  
28 -// httpServletResponse.setHeader(JwtUtils.getHeader(), jwt);  
29 -// ServletOutputStream outputStream = httpServletResponse.getOutputStream();  
30 -// outputStream.write(JSON.toJSONString(ErrorCode.SUCCESS).getBytes(StandardCharsets.UTF_8));  
31 -// outputStream.flush();  
32 -// outputStream.close();  
33 -  
34 -// logger.info("[登录成功] - [{}]", username);  
35 - }  
36 -}  
src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
@@ -53,14 +53,10 @@ public class SecurityUtils { @@ -53,14 +53,10 @@ public class SecurityUtils {
53 Authentication authentication = getAuthentication(); 53 Authentication authentication = getAuthentication();
54 if(authentication!=null){ 54 if(authentication!=null){
55 Object principal = authentication.getPrincipal(); 55 Object principal = authentication.getPrincipal();
56 - if(principal!=null && !"anonymousUser".equals(principal)){  
57 -// LoginUser user = (LoginUser) authentication.getPrincipal(); 56 + if(principal!=null && !"anonymousUser".equals(principal.toString())){
58 57
59 - String username = (String) principal;  
60 - User user = new User();  
61 - user.setUsername(username);  
62 - LoginUser loginUser = new LoginUser(user, LocalDateTime.now());  
63 - return loginUser; 58 + User user = (User) principal;
  59 + return new LoginUser(user, LocalDateTime.now());
64 } 60 }
65 } 61 }
66 return null; 62 return null;
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -47,16 +47,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @@ -47,16 +47,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
47 * 登出成功的处理 47 * 登出成功的处理
48 */ 48 */
49 @Autowired 49 @Autowired
50 - private LoginFailureHandler loginFailureHandler;  
51 - /**  
52 - * 登录成功的处理  
53 - */  
54 - @Autowired  
55 - private LoginSuccessHandler loginSuccessHandler;  
56 - /**  
57 - * 登出成功的处理  
58 - */  
59 - @Autowired  
60 private LogoutHandler logoutHandler; 50 private LogoutHandler logoutHandler;
61 /** 51 /**
62 * 未登录的处理 52 * 未登录的处理
src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java
@@ -25,6 +25,8 @@ public class JwtUser { @@ -25,6 +25,8 @@ public class JwtUser {
25 25
26 private String password; 26 private String password;
27 27
  28 + private int roleId;
  29 +
28 private TokenStatus status; 30 private TokenStatus status;
29 31
30 public String getUserName() { 32 public String getUserName() {
@@ -50,4 +52,12 @@ public class JwtUser { @@ -50,4 +52,12 @@ public class JwtUser {
50 public void setPassword(String password) { 52 public void setPassword(String password) {
51 this.password = password; 53 this.password = password;
52 } 54 }
  55 +
  56 + public int getRoleId() {
  57 + return roleId;
  58 + }
  59 +
  60 + public void setRoleId(int roleId) {
  61 + this.roleId = roleId;
  62 + }
53 } 63 }
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -36,8 +36,6 @@ public class SipLayer implements CommandLineRunner { @@ -36,8 +36,6 @@ public class SipLayer implements CommandLineRunner {
36 private final Map<String, SipProviderImpl> tcpSipProviderMap = new ConcurrentHashMap<>(); 36 private final Map<String, SipProviderImpl> tcpSipProviderMap = new ConcurrentHashMap<>();
37 private final Map<String, SipProviderImpl> udpSipProviderMap = new ConcurrentHashMap<>(); 37 private final Map<String, SipProviderImpl> udpSipProviderMap = new ConcurrentHashMap<>();
38 38
39 - private SipFactory sipFactory;  
40 -  
41 @Override 39 @Override
42 public void run(String... args) { 40 public void run(String... args) {
43 List<String> monitorIps = new ArrayList<>(); 41 List<String> monitorIps = new ArrayList<>();
@@ -50,8 +48,7 @@ public class SipLayer implements CommandLineRunner { @@ -50,8 +48,7 @@ public class SipLayer implements CommandLineRunner {
50 monitorIps.add(sipConfig.getIp()); 48 monitorIps.add(sipConfig.getIp());
51 } 49 }
52 50
53 - sipFactory = SipFactory.getInstance();  
54 - sipFactory.setPathName("gov.nist"); 51 + SipFactory.getInstance().setPathName("gov.nist");
55 if (monitorIps.size() > 0) { 52 if (monitorIps.size() > 0) {
56 for (String monitorIp : monitorIps) { 53 for (String monitorIp : monitorIps) {
57 addListeningPoint(monitorIp, sipConfig.getPort()); 54 addListeningPoint(monitorIp, sipConfig.getPort());
@@ -65,7 +62,7 @@ public class SipLayer implements CommandLineRunner { @@ -65,7 +62,7 @@ public class SipLayer implements CommandLineRunner {
65 private void addListeningPoint(String monitorIp, int port){ 62 private void addListeningPoint(String monitorIp, int port){
66 SipStackImpl sipStack; 63 SipStackImpl sipStack;
67 try { 64 try {
68 - sipStack = (SipStackImpl)sipFactory.createSipStack(DefaultProperties.getProperties(monitorIp, userSetting.getSipLog())); 65 + sipStack = (SipStackImpl)SipFactory.getInstance().createSipStack(DefaultProperties.getProperties(monitorIp, userSetting.getSipLog()));
69 } catch (PeerUnavailableException e) { 66 } catch (PeerUnavailableException e) {
70 logger.error("[Sip Server] SIP服务启动失败, 监听地址{}失败,请检查ip是否正确", monitorIp); 67 logger.error("[Sip Server] SIP服务启动失败, 监听地址{}失败,请检查ip是否正确", monitorIp);
71 return; 68 return;
@@ -106,10 +103,6 @@ public class SipLayer implements CommandLineRunner { @@ -106,10 +103,6 @@ public class SipLayer implements CommandLineRunner {
106 } 103 }
107 } 104 }
108 105
109 - public SipFactory getSipFactory() {  
110 - return sipFactory;  
111 - }  
112 -  
113 public SipProviderImpl getUdpSipProvider(String ip) { 106 public SipProviderImpl getUdpSipProvider(String ip) {
114 if (ObjectUtils.isEmpty(ip)) { 107 if (ObjectUtils.isEmpty(ip)) {
115 return null; 108 return null;
src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdSendFailEvent.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.gb28181.bean;  
2 -  
3 -import javax.sip.Dialog;  
4 -import java.util.EventObject;  
5 -  
6 -public class CmdSendFailEvent extends EventObject {  
7 -  
8 - private String callId;  
9 -  
10 - /**  
11 - * Constructs a prototypical Event.  
12 - *  
13 - * @param dialog  
14 - * @throws IllegalArgumentException if source is null.  
15 - */  
16 - public CmdSendFailEvent(Dialog dialog) {  
17 - super(dialog);  
18 - }  
19 -  
20 - public String getCallId() {  
21 - return callId;  
22 - }  
23 -  
24 - public void setCallId(String callId) {  
25 - this.callId = callId;  
26 - }  
27 -}  
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -247,6 +247,17 @@ public class Device { @@ -247,6 +247,17 @@ public class Device {
247 return streamMode; 247 return streamMode;
248 } 248 }
249 249
  250 + public Integer getStreamModeForParam() {
  251 + if (streamMode.equalsIgnoreCase("UDP")) {
  252 + return 0;
  253 + }else if (streamMode.equalsIgnoreCase("TCP-PASSIVE")) {
  254 + return 1;
  255 + }else if (streamMode.equalsIgnoreCase("TCP-ACTIVE")) {
  256 + return 2;
  257 + }
  258 + return 0;
  259 + }
  260 +
250 public void setStreamMode(String streamMode) { 261 public void setStreamMode(String streamMode) {
251 this.streamMode = streamMode; 262 this.streamMode = streamMode;
252 } 263 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java
@@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean; @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 public enum InviteStreamType { 3 public enum InviteStreamType {
4 4
5 - PLAY,PLAYBACK,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY,BROADCAST,TALK 5 + PLAY,PLAYBACK,DOWNLOAD,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY,BROADCAST,TALK
6 6
7 7
8 } 8 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java
1 package com.genersoft.iot.vmp.gb28181.bean; 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 3 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 4
5 public class SsrcTransaction { 5 public class SsrcTransaction {
6 6
@@ -13,7 +13,7 @@ public class SsrcTransaction { @@ -13,7 +13,7 @@ public class SsrcTransaction {
13 13
14 private SipTransactionInfo sipTransactionInfo; 14 private SipTransactionInfo sipTransactionInfo;
15 15
16 - private VideoStreamSessionManager.SessionType type; 16 + private InviteSessionType type;
17 17
18 public String getDeviceId() { 18 public String getDeviceId() {
19 return deviceId; 19 return deviceId;
@@ -63,11 +63,11 @@ public class SsrcTransaction { @@ -63,11 +63,11 @@ public class SsrcTransaction {
63 this.ssrc = ssrc; 63 this.ssrc = ssrc;
64 } 64 }
65 65
66 - public VideoStreamSessionManager.SessionType getType() { 66 + public InviteSessionType getType() {
67 return type; 67 return type;
68 } 68 }
69 69
70 - public void setType(VideoStreamSessionManager.SessionType type) { 70 + public void setType(InviteSessionType type) {
71 this.type = type; 71 this.type = type;
72 } 72 }
73 73
src/main/java/com/genersoft/iot/vmp/gb28181/conf/ServerLoggerImpl.java
@@ -27,7 +27,7 @@ public class ServerLoggerImpl implements ServerLogger { @@ -27,7 +27,7 @@ public class ServerLoggerImpl implements ServerLogger {
27 return; 27 return;
28 } 28 }
29 StringBuilder stringBuilder = new StringBuilder(); 29 StringBuilder stringBuilder = new StringBuilder();
30 - stringBuilder.append(!sender? "发送:目标--->" + from:"接收:来自--->" + to) 30 + stringBuilder.append(sender? "发送:目标--->" + from:"接收:来自--->" + to)
31 .append("\r\n") 31 .append("\r\n")
32 .append(message); 32 .append(message);
33 this.stackLogger.logInfo(stringBuilder.toString()); 33 this.stackLogger.logInfo(stringBuilder.toString());
@@ -40,7 +40,7 @@ public class ServerLoggerImpl implements ServerLogger { @@ -40,7 +40,7 @@ public class ServerLoggerImpl implements ServerLogger {
40 return; 40 return;
41 } 41 }
42 StringBuilder stringBuilder = new StringBuilder(); 42 StringBuilder stringBuilder = new StringBuilder();
43 - stringBuilder.append(!sender? "发送: 目标->" + from :"接收:来自->" + to) 43 + stringBuilder.append(sender? "发送: 目标->" + from :"接收:来自->" + to)
44 .append("\r\n") 44 .append("\r\n")
45 .append(message); 45 .append(message);
46 this.stackLogger.logInfo(stringBuilder.toString()); 46 this.stackLogger.logInfo(stringBuilder.toString());
@@ -52,7 +52,7 @@ public class ServerLoggerImpl implements ServerLogger { @@ -52,7 +52,7 @@ public class ServerLoggerImpl implements ServerLogger {
52 return; 52 return;
53 } 53 }
54 StringBuilder stringBuilder = new StringBuilder(); 54 StringBuilder stringBuilder = new StringBuilder();
55 - stringBuilder.append(!sender? "发送: 目标->" + from :"接收:来自->" + to) 55 + stringBuilder.append(sender? "发送: 目标->" + from :"接收:来自->" + to)
56 .append("\r\n") 56 .append("\r\n")
57 .append(message); 57 .append(message);
58 this.stackLogger.logInfo(stringBuilder.toString()); 58 this.stackLogger.logInfo(stringBuilder.toString());
@@ -87,6 +87,4 @@ public class ServerLoggerImpl implements ServerLogger { @@ -87,6 +87,4 @@ public class ServerLoggerImpl implements ServerLogger {
87 this.stackLogger = this.sipStack.getStackLogger(); 87 this.stackLogger = this.sipStack.getStackLogger();
88 } 88 }
89 } 89 }
90 -  
91 -  
92 } 90 }
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
@@ -76,7 +76,11 @@ public class SipSubscribe { @@ -76,7 +76,11 @@ public class SipSubscribe {
76 // 会话已结束 76 // 会话已结束
77 dialogTerminated, 77 dialogTerminated,
78 // 设备未找到 78 // 设备未找到
79 - deviceNotFoundEvent 79 + deviceNotFoundEvent,
  80 + // 消息发送失败
  81 + cmdSendFailEvent,
  82 + // 消息发送失败
  83 + failedToGetPort
80 } 84 }
81 85
82 public static class EventResult<EventObject>{ 86 public static class EventResult<EventObject>{
@@ -86,9 +90,7 @@ public class SipSubscribe { @@ -86,9 +90,7 @@ public class SipSubscribe {
86 public String callId; 90 public String callId;
87 public EventObject event; 91 public EventObject event;
88 92
89 - public EventResult(int statusCode, String msg) {  
90 - this.statusCode = statusCode;  
91 - this.msg = msg; 93 + public EventResult() {
92 } 94 }
93 95
94 public EventResult(EventObject event) { 96 public EventResult(EventObject event) {
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
1 package com.genersoft.iot.vmp.gb28181.event.subscribe.catalog; 1 package com.genersoft.iot.vmp.gb28181.event.subscribe.catalog;
2 2
3 -import com.genersoft.iot.vmp.common.VideoManagerConstants;  
4 -import com.genersoft.iot.vmp.conf.SipConfig;  
5 import com.genersoft.iot.vmp.conf.UserSetting; 3 import com.genersoft.iot.vmp.conf.UserSetting;
6 import com.genersoft.iot.vmp.gb28181.bean.*; 4 import com.genersoft.iot.vmp.gb28181.bean.*;
7 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
8 -import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;  
9 import com.genersoft.iot.vmp.service.IGbStreamService; 6 import com.genersoft.iot.vmp.service.IGbStreamService;
10 -import com.genersoft.iot.vmp.service.IMediaServerService;  
11 -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;  
12 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 7 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
13 import org.slf4j.Logger; 8 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory; 9 import org.slf4j.LoggerFactory;
@@ -16,12 +11,14 @@ import org.springframework.beans.factory.annotation.Autowired; @@ -16,12 +11,14 @@ import org.springframework.beans.factory.annotation.Autowired;
16 import org.springframework.context.ApplicationListener; 11 import org.springframework.context.ApplicationListener;
17 import org.springframework.stereotype.Component; 12 import org.springframework.stereotype.Component;
18 import org.springframework.util.ObjectUtils; 13 import org.springframework.util.ObjectUtils;
19 -import org.springframework.util.StringUtils;  
20 14
21 import javax.sip.InvalidArgumentException; 15 import javax.sip.InvalidArgumentException;
22 import javax.sip.SipException; 16 import javax.sip.SipException;
23 import java.text.ParseException; 17 import java.text.ParseException;
24 -import java.util.*; 18 +import java.util.ArrayList;
  19 +import java.util.HashMap;
  20 +import java.util.List;
  21 +import java.util.Map;
25 22
26 /** 23 /**
27 * catalog事件 24 * catalog事件
@@ -43,6 +40,9 @@ public class CatalogEventLister implements ApplicationListener&lt;CatalogEvent&gt; { @@ -43,6 +40,9 @@ public class CatalogEventLister implements ApplicationListener&lt;CatalogEvent&gt; {
43 @Autowired 40 @Autowired
44 private SubscribeHolder subscribeHolder; 41 private SubscribeHolder subscribeHolder;
45 42
  43 + @Autowired
  44 + private UserSetting userSetting;
  45 +
46 @Override 46 @Override
47 public void onApplicationEvent(CatalogEvent event) { 47 public void onApplicationEvent(CatalogEvent event) {
48 SubscribeInfo subscribe = null; 48 SubscribeInfo subscribe = null;
@@ -93,6 +93,9 @@ public class CatalogEventLister implements ApplicationListener&lt;CatalogEvent&gt; { @@ -93,6 +93,9 @@ public class CatalogEventLister implements ApplicationListener&lt;CatalogEvent&gt; {
93 } 93 }
94 if (event.getGbStreams() != null && event.getGbStreams().size() > 0){ 94 if (event.getGbStreams() != null && event.getGbStreams().size() > 0){
95 for (GbStream gbStream : event.getGbStreams()) { 95 for (GbStream gbStream : event.getGbStreams()) {
  96 + if (gbStream.getStreamType().equals("push") && !userSetting.isUsePushingAsStatus()) {
  97 + continue;
  98 + }
96 DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform); 99 DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform);
97 deviceChannelList.add(deviceChannelByStream); 100 deviceChannelList.add(deviceChannelByStream);
98 } 101 }
src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.session;
  2 +
  3 +import com.genersoft.iot.vmp.conf.SipConfig;
  4 +import org.springframework.beans.factory.annotation.Autowired;
  5 +import org.springframework.data.redis.core.StringRedisTemplate;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +import java.util.ArrayList;
  9 +import java.util.List;
  10 +import java.util.Set;
  11 +
  12 +/**
  13 + * ssrc使用
  14 + */
  15 +@Component
  16 +public class SSRCFactory {
  17 +
  18 + /**
  19 + * 播流最大并发个数
  20 + */
  21 + private static final Integer MAX_STREAM_COUNT = 10000;
  22 +
  23 + /**
  24 + * 播流最大并发个数
  25 + */
  26 + private static final String SSRC_INFO_KEY = "VMP_SSRC_INFO_";
  27 +
  28 + @Autowired
  29 + private StringRedisTemplate redisTemplate;
  30 +
  31 + @Autowired
  32 + private SipConfig sipConfig;
  33 +
  34 +
  35 + public void initMediaServerSSRC(String mediaServerId, Set<String> usedSet) {
  36 + String ssrcPrefix = sipConfig.getDomain().substring(3, 8);
  37 + String redisKey = SSRC_INFO_KEY + mediaServerId;
  38 + List<String> ssrcList = new ArrayList<>();
  39 + for (int i = 1; i < MAX_STREAM_COUNT; i++) {
  40 + String ssrc = String.format("%s%04d", ssrcPrefix, i);
  41 +
  42 + if (null == usedSet || !usedSet.contains(ssrc)) {
  43 + ssrcList.add(ssrc);
  44 +
  45 + }
  46 + }
  47 + if (redisTemplate.opsForSet().size(redisKey) != null) {
  48 + redisTemplate.delete(redisKey);
  49 + }
  50 + redisTemplate.opsForSet().add(redisKey, ssrcList.toArray(new String[0]));
  51 + }
  52 +
  53 +
  54 + /**
  55 + * 获取视频预览的SSRC值,第一位固定为0
  56 + *
  57 + * @return ssrc
  58 + */
  59 + public String getPlaySsrc(String mediaServerId) {
  60 + return "0" + getSN(mediaServerId);
  61 + }
  62 +
  63 + /**
  64 + * 获取录像回放的SSRC值,第一位固定为1
  65 + */
  66 + public String getPlayBackSsrc(String mediaServerId) {
  67 + return "1" + getSN(mediaServerId);
  68 + }
  69 +
  70 + /**
  71 + * 释放ssrc,主要用完的ssrc一定要释放,否则会耗尽
  72 + *
  73 + * @param ssrc 需要重置的ssrc
  74 + */
  75 + public void releaseSsrc(String mediaServerId, String ssrc) {
  76 + if (ssrc == null) {
  77 + return;
  78 + }
  79 + String sn = ssrc.substring(1);
  80 + String redisKey = SSRC_INFO_KEY + mediaServerId;
  81 + redisTemplate.opsForSet().add(redisKey, sn);
  82 + }
  83 +
  84 + /**
  85 + * 获取后四位数SN,随机数
  86 + */
  87 + private String getSN(String mediaServerId) {
  88 + String sn = null;
  89 + String redisKey = SSRC_INFO_KEY + mediaServerId;
  90 + Long size = redisTemplate.opsForSet().size(redisKey);
  91 + if (size == null || size == 0) {
  92 + throw new RuntimeException("ssrc已经用完");
  93 + } else {
  94 + // 在集合中移除并返回一个随机成员。
  95 + sn = (String) redisTemplate.opsForSet().pop(redisKey);
  96 + redisTemplate.opsForSet().remove(redisKey, sn);
  97 + }
  98 + return sn;
  99 + }
  100 +
  101 + /**
  102 + * 重置一个流媒体服务的所有ssrc
  103 + *
  104 + * @param mediaServerId 流媒体服务ID
  105 + */
  106 + public void reset(String mediaServerId) {
  107 + this.initMediaServerSSRC(mediaServerId, null);
  108 + }
  109 +
  110 + /**
  111 + * 是否已经存在了某个MediaServer的SSRC信息
  112 + *
  113 + * @param mediaServerId 流媒体服务ID
  114 + */
  115 + public boolean hasMediaServerSSRC(String mediaServerId) {
  116 + String redisKey = SSRC_INFO_KEY + mediaServerId;
  117 + return redisTemplate.opsForSet().members(redisKey) != null;
  118 + }
  119 +
  120 + /**
  121 + * 查询ssrc是否可用
  122 + *
  123 + * @param mediaServerId
  124 + * @param ssrc
  125 + * @return
  126 + */
  127 + public boolean checkSsrc(String mediaServerId, String ssrc) {
  128 + String sn = ssrc.substring(1);
  129 + String redisKey = SSRC_INFO_KEY + mediaServerId;
  130 + return redisTemplate.opsForSet().isMember(redisKey, sn) != null;
  131 + }
  132 +}
src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.gb28181.session;  
2 -  
3 -import com.genersoft.iot.vmp.utils.ConfigConst;  
4 -import io.swagger.v3.oas.annotations.media.Schema;  
5 -  
6 -import java.util.ArrayList;  
7 -import java.util.List;  
8 -import java.util.Random;  
9 -import java.util.Set;  
10 -  
11 -@Schema(description = "ssrc信息")  
12 -public class SsrcConfig {  
13 -  
14 - /**  
15 - * zlm流媒体服务器Id  
16 - */  
17 - @Schema(description = "流媒体服务器Id")  
18 - private String mediaServerId;  
19 -  
20 - @Schema(description = "SSRC前缀")  
21 - private String ssrcPrefix;  
22 -  
23 - /**  
24 - * zlm流媒体服务器已用会话句柄  
25 - */  
26 - @Schema(description = "zlm流媒体服务器已用会话句柄")  
27 - private List<String> isUsed;  
28 -  
29 - /**  
30 - * zlm流媒体服务器可用会话句柄  
31 - */  
32 - @Schema(description = "zlm流媒体服务器可用会话句柄")  
33 - private List<String> notUsed;  
34 -  
35 - public SsrcConfig() {  
36 - }  
37 -  
38 - public SsrcConfig(String mediaServerId, Set<String> usedSet, String sipDomain) {  
39 - this.mediaServerId = mediaServerId;  
40 - this.isUsed = new ArrayList<>();  
41 - this.ssrcPrefix = sipDomain.substring(3, 8);  
42 - this.notUsed = new ArrayList<>();  
43 - for (int i = 1; i < ConfigConst.MAX_STRTEAM_COUNT; i++) {  
44 - String ssrc;  
45 - if (i < 10) {  
46 - ssrc = "000" + i;  
47 - } else if (i < 100) {  
48 - ssrc = "00" + i;  
49 - } else if (i < 1000) {  
50 - ssrc = "0" + i;  
51 - } else {  
52 - ssrc = String.valueOf(i);  
53 - }  
54 - if (null == usedSet || !usedSet.contains(ssrc)) {  
55 - this.notUsed.add(ssrc);  
56 - } else {  
57 - this.isUsed.add(ssrc);  
58 - }  
59 - }  
60 - }  
61 -  
62 -  
63 - /**  
64 - * 获取视频预览的SSRC值,第一位固定为0  
65 - * @return ssrc  
66 - */  
67 - public String getPlaySsrc() {  
68 - return "0" + getSsrcPrefix() + getSN();  
69 - }  
70 -  
71 - /**  
72 - * 获取录像回放的SSRC值,第一位固定为1  
73 - *  
74 - */  
75 - public String getPlayBackSsrc() {  
76 - return "1" + getSsrcPrefix() + getSN();  
77 - }  
78 -  
79 - /**  
80 - * 释放ssrc,主要用完的ssrc一定要释放,否则会耗尽  
81 - * @param ssrc 需要重置的ssrc  
82 - */  
83 - public void releaseSsrc(String ssrc) {  
84 - if (ssrc == null) {  
85 - return;  
86 - }  
87 - String sn = ssrc.substring(6);  
88 - try {  
89 - isUsed.remove(sn);  
90 - notUsed.add(sn);  
91 - }catch (NullPointerException e){  
92 - }  
93 - }  
94 -  
95 - /**  
96 - * 获取后四位数SN,随机数  
97 - *  
98 - */  
99 - private String getSN() {  
100 - String sn = null;  
101 - int index = 0;  
102 - if (notUsed.size() == 0) {  
103 - throw new RuntimeException("ssrc已经用完");  
104 - } else if (notUsed.size() == 1) {  
105 - sn = notUsed.get(0);  
106 - } else {  
107 - index = new Random().nextInt(notUsed.size() - 1);  
108 - sn = notUsed.get(index);  
109 - }  
110 - notUsed.remove(index);  
111 - isUsed.add(sn);  
112 - return sn;  
113 - }  
114 -  
115 - public String getSsrcPrefix() {  
116 - return ssrcPrefix;  
117 - }  
118 -  
119 - public String getMediaServerId() {  
120 - return mediaServerId;  
121 - }  
122 -  
123 - public void setMediaServerId(String mediaServerId) {  
124 - this.mediaServerId = mediaServerId;  
125 - }  
126 -  
127 - public void setSsrcPrefix(String ssrcPrefix) {  
128 - this.ssrcPrefix = ssrcPrefix;  
129 - }  
130 -  
131 - public List<String> getIsUsed() {  
132 - return isUsed;  
133 - }  
134 -  
135 - public void setIsUsed(List<String> isUsed) {  
136 - this.isUsed = isUsed;  
137 - }  
138 -  
139 - public List<String> getNotUsed() {  
140 - return notUsed;  
141 - }  
142 -  
143 - public void setNotUsed(List<String> notUsed) {  
144 - this.notUsed = notUsed;  
145 - }  
146 -  
147 - public boolean checkSsrc(String ssrcInResponse) {  
148 - return !isUsed.contains(ssrcInResponse);  
149 - }  
150 -}  
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
1 package com.genersoft.iot.vmp.gb28181.session; 1 package com.genersoft.iot.vmp.gb28181.session;
2 2
  3 +import com.genersoft.iot.vmp.common.InviteSessionType;
3 import com.genersoft.iot.vmp.common.VideoManagerConstants; 4 import com.genersoft.iot.vmp.common.VideoManagerConstants;
4 import com.genersoft.iot.vmp.conf.UserSetting; 5 import com.genersoft.iot.vmp.conf.UserSetting;
5 import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; 6 import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
@@ -27,14 +28,6 @@ public class VideoStreamSessionManager { @@ -27,14 +28,6 @@ public class VideoStreamSessionManager {
27 @Autowired 28 @Autowired
28 private RedisTemplate<Object, Object> redisTemplate; 29 private RedisTemplate<Object, Object> redisTemplate;
29 30
30 - public enum SessionType {  
31 - play,  
32 - playback,  
33 - download,  
34 - broadcast,  
35 - talk  
36 - }  
37 -  
38 /** 31 /**
39 * 添加一个点播/回放的事务信息 32 * 添加一个点播/回放的事务信息
40 * 后续可以通过流Id/callID 33 * 后续可以通过流Id/callID
@@ -45,7 +38,7 @@ public class VideoStreamSessionManager { @@ -45,7 +38,7 @@ public class VideoStreamSessionManager {
45 * @param mediaServerId 所使用的流媒体ID 38 * @param mediaServerId 所使用的流媒体ID
46 * @param response 回复 39 * @param response 回复
47 */ 40 */
48 - public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, SessionType type){ 41 + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type){
49 SsrcTransaction ssrcTransaction = new SsrcTransaction(); 42 SsrcTransaction ssrcTransaction = new SsrcTransaction();
50 ssrcTransaction.setDeviceId(deviceId); 43 ssrcTransaction.setDeviceId(deviceId);
51 ssrcTransaction.setChannelId(channelId); 44 ssrcTransaction.setChannelId(channelId);
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
@@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.UserSetting; @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.UserSetting;
5 import com.genersoft.iot.vmp.gb28181.bean.Device; 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
7 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 7 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  8 +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
8 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; 9 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
9 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; 10 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
10 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -38,6 +39,9 @@ public class SipRunner implements CommandLineRunner { @@ -38,6 +39,9 @@ public class SipRunner implements CommandLineRunner {
38 private IRedisCatchStorage redisCatchStorage; 39 private IRedisCatchStorage redisCatchStorage;
39 40
40 @Autowired 41 @Autowired
  42 + private SSRCFactory ssrcFactory;
  43 +
  44 + @Autowired
41 private UserSetting userSetting; 45 private UserSetting userSetting;
42 46
43 @Autowired 47 @Autowired
@@ -96,6 +100,7 @@ public class SipRunner implements CommandLineRunner { @@ -96,6 +100,7 @@ public class SipRunner implements CommandLineRunner {
96 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId()); 100 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
97 redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStream()); 101 redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStream());
98 if (mediaServerItem != null) { 102 if (mediaServerItem != null) {
  103 + ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
99 Map<String, Object> param = new HashMap<>(); 104 Map<String, Object> param = new HashMap<>();
100 param.put("vhost","__defaultVhost__"); 105 param.put("vhost","__defaultVhost__");
101 param.put("app",sendRtpItem.getApp()); 106 param.put("app",sendRtpItem.getApp());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java
@@ -46,8 +46,7 @@ public class SIPSender { @@ -46,8 +46,7 @@ public class SIPSender {
46 transmitRequest(ip, message, errorEvent, null); 46 transmitRequest(ip, message, errorEvent, null);
47 } 47 }
48 48
49 - public void transmitRequest(String ip, Message message, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, ParseException {  
50 - try { 49 + public void transmitRequest(String ip, Message message, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException {
51 ViaHeader viaHeader = (ViaHeader)message.getHeader(ViaHeader.NAME); 50 ViaHeader viaHeader = (ViaHeader)message.getHeader(ViaHeader.NAME);
52 String transport = "UDP"; 51 String transport = "UDP";
53 if (viaHeader == null) { 52 if (viaHeader == null) {
@@ -57,7 +56,7 @@ public class SIPSender { @@ -57,7 +56,7 @@ public class SIPSender {
57 } 56 }
58 if (message.getHeader(UserAgentHeader.NAME) == null) { 57 if (message.getHeader(UserAgentHeader.NAME) == null) {
59 try { 58 try {
60 - message.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 59 + message.addHeader(SipUtils.createUserAgentHeader(gitUtil));
61 } catch (ParseException e) { 60 } catch (ParseException e) {
62 logger.error("添加UserAgentHeader失败", e); 61 logger.error("添加UserAgentHeader失败", e);
63 } 62 }
@@ -104,9 +103,6 @@ public class SIPSender { @@ -104,9 +103,6 @@ public class SIPSender {
104 sipProvider.sendResponse((Response)message); 103 sipProvider.sendResponse((Response)message);
105 } 104 }
106 } 105 }
107 - } finally {  
108 -// logger.info("[SEND]:SUCCESS:{}", message);  
109 - }  
110 } 106 }
111 107
112 public CallIdHeader getNewCallIdHeader(String ip, String transport){ 108 public CallIdHeader getNewCallIdHeader(String ip, String transport){
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd; @@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
3 import com.genersoft.iot.vmp.common.StreamInfo; 3 import com.genersoft.iot.vmp.common.StreamInfo;
4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 import com.genersoft.iot.vmp.gb28181.bean.*; 5 import com.genersoft.iot.vmp.gb28181.bean.*;
  6 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  7 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
6 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 8 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
7 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 9 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
8 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 10 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -107,7 +109,7 @@ public interface ISIPCommander { @@ -107,7 +109,7 @@ public interface ISIPCommander {
107 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss 109 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
108 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss 110 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
109 */ 111 */
110 - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; 112 + void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
111 113
112 /** 114 /**
113 * 请求历史媒体下载 115 * 请求历史媒体下载
@@ -119,7 +121,7 @@ public interface ISIPCommander { @@ -119,7 +121,7 @@ public interface ISIPCommander {
119 * @param downloadSpeed 下载倍速参数 121 * @param downloadSpeed 下载倍速参数
120 */ 122 */
121 void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 123 void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
122 - String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, 124 + String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,
123 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; 125 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
124 126
125 127
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
@@ -17,6 +17,7 @@ import org.springframework.util.DigestUtils; @@ -17,6 +17,7 @@ import org.springframework.util.DigestUtils;
17 17
18 import javax.sip.InvalidArgumentException; 18 import javax.sip.InvalidArgumentException;
19 import javax.sip.PeerUnavailableException; 19 import javax.sip.PeerUnavailableException;
  20 +import javax.sip.SipFactory;
20 import javax.sip.address.Address; 21 import javax.sip.address.Address;
21 import javax.sip.address.SipURI; 22 import javax.sip.address.SipURI;
22 import javax.sip.header.*; 23 import javax.sip.header.*;
@@ -50,39 +51,39 @@ public class SIPRequestHeaderPlarformProvider { @@ -50,39 +51,39 @@ public class SIPRequestHeaderPlarformProvider {
50 Request request = null; 51 Request request = null;
51 String sipAddress = parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort(); 52 String sipAddress = parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort();
52 //请求行 53 //请求行
53 - SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), 54 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(),
54 parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); 55 parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
55 //via 56 //via
56 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 57 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
57 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(), 58 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(),
58 parentPlatform.getServerPort(), parentPlatform.getTransport(), SipUtils.getNewViaTag()); 59 parentPlatform.getServerPort(), parentPlatform.getTransport(), SipUtils.getNewViaTag());
59 viaHeader.setRPort(); 60 viaHeader.setRPort();
60 viaHeaders.add(viaHeader); 61 viaHeaders.add(viaHeader);
61 //from 62 //from
62 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), sipConfig.getDomain());  
63 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
64 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag); 63 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), sipConfig.getDomain());
  64 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  65 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag);
65 //to 66 //to
66 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), sipConfig.getDomain());  
67 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
68 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,toTag); 67 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), sipConfig.getDomain());
  68 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  69 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,toTag);
69 70
70 //Forwards 71 //Forwards
71 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 72 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
72 73
73 //ceq 74 //ceq
74 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(CSeq, Request.REGISTER);  
75 - request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestLine, Request.REGISTER, callIdHeader, 75 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(CSeq, Request.REGISTER);
  76 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.REGISTER, callIdHeader,
76 cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); 77 cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
77 78
78 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory() 79 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory()
79 .createSipURI(parentPlatform.getDeviceGBId(), sipAddress)); 80 .createSipURI(parentPlatform.getDeviceGBId(), sipAddress));
80 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 81 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
81 82
82 - ExpiresHeader expiresHeader = sipLayer.getSipFactory().createHeaderFactory().createExpiresHeader(expires); 83 + ExpiresHeader expiresHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires);
83 request.addHeader(expiresHeader); 84 request.addHeader(expiresHeader);
84 85
85 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 86 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
86 87
87 return request; 88 return request;
88 } 89 }
@@ -92,9 +93,9 @@ public class SIPRequestHeaderPlarformProvider { @@ -92,9 +93,9 @@ public class SIPRequestHeaderPlarformProvider {
92 93
93 94
94 Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, toTag, callIdHeader, expires); 95 Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, toTag, callIdHeader, expires);
95 - SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); 96 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
96 if (www == null) { 97 if (www == null) {
97 - AuthorizationHeader authorizationHeader = sipLayer.getSipFactory().createHeaderFactory().createAuthorizationHeader("Digest"); 98 + AuthorizationHeader authorizationHeader = SipFactory.getInstance().createHeaderFactory().createAuthorizationHeader("Digest");
98 String username = parentPlatform.getUsername(); 99 String username = parentPlatform.getUsername();
99 if ( username == null || username == "" ) 100 if ( username == null || username == "" )
100 { 101 {
@@ -147,7 +148,7 @@ public class SIPRequestHeaderPlarformProvider { @@ -147,7 +148,7 @@ public class SIPRequestHeaderPlarformProvider {
147 148
148 String RESPONSE = DigestUtils.md5DigestAsHex(reStr.toString().getBytes()); 149 String RESPONSE = DigestUtils.md5DigestAsHex(reStr.toString().getBytes());
149 150
150 - AuthorizationHeader authorizationHeader = sipLayer.getSipFactory().createHeaderFactory().createAuthorizationHeader(scheme); 151 + AuthorizationHeader authorizationHeader = SipFactory.getInstance().createHeaderFactory().createAuthorizationHeader(scheme);
151 authorizationHeader.setUsername(parentPlatform.getDeviceGBId()); 152 authorizationHeader.setUsername(parentPlatform.getDeviceGBId());
152 authorizationHeader.setRealm(realm); 153 authorizationHeader.setRealm(realm);
153 authorizationHeader.setNonce(nonce); 154 authorizationHeader.setNonce(nonce);
@@ -165,7 +166,7 @@ public class SIPRequestHeaderPlarformProvider { @@ -165,7 +166,7 @@ public class SIPRequestHeaderPlarformProvider {
165 } 166 }
166 167
167 public Request createMessageRequest(ParentPlatform parentPlatform, String content, SendRtpItem sendRtpItem) throws PeerUnavailableException, ParseException, InvalidArgumentException { 168 public Request createMessageRequest(ParentPlatform parentPlatform, String content, SendRtpItem sendRtpItem) throws PeerUnavailableException, ParseException, InvalidArgumentException {
168 - CallIdHeader callIdHeader = sipLayer.getSipFactory().createHeaderFactory().createCallIdHeader(sendRtpItem.getCallId()); 169 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(sendRtpItem.getCallId());
169 return createMessageRequest(parentPlatform, content, sendRtpItem.getToTag(), SipUtils.getNewViaTag(), sendRtpItem.getFromTag(), callIdHeader); 170 return createMessageRequest(parentPlatform, content, sendRtpItem.getToTag(), SipUtils.getNewViaTag(), sendRtpItem.getFromTag(), callIdHeader);
170 } 171 }
171 172
@@ -178,36 +179,36 @@ public class SIPRequestHeaderPlarformProvider { @@ -178,36 +179,36 @@ public class SIPRequestHeaderPlarformProvider {
178 Request request = null; 179 Request request = null;
179 String serverAddress = parentPlatform.getServerIP()+ ":" + parentPlatform.getServerPort(); 180 String serverAddress = parentPlatform.getServerIP()+ ":" + parentPlatform.getServerPort();
180 // sipuri 181 // sipuri
181 - SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), serverAddress); 182 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), serverAddress);
182 // via 183 // via
183 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 184 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
184 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), parentPlatform.getDevicePort(), 185 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), parentPlatform.getDevicePort(),
185 parentPlatform.getTransport(), viaTag); 186 parentPlatform.getTransport(), viaTag);
186 viaHeader.setRPort(); 187 viaHeader.setRPort();
187 viaHeaders.add(viaHeader); 188 viaHeaders.add(viaHeader);
188 // from 189 // from
189 - // SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), parentPlatform.getDeviceIp() + ":" + parentPlatform.getDeviceIp());  
190 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), sipConfig.getDomain());  
191 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
192 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag); 190 + // SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), parentPlatform.getDeviceIp() + ":" + parentPlatform.getDeviceIp());
  191 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), sipConfig.getDomain());
  192 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  193 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag);
193 // to 194 // to
194 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), serverAddress);  
195 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
196 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress, toTag); 195 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), serverAddress);
  196 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  197 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag);
197 198
198 // Forwards 199 // Forwards
199 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 200 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
200 // ceq 201 // ceq
201 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);  
202 - MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipLayer.getSipFactory().createMessageFactory(); 202 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);
  203 + MessageFactoryImpl messageFactory = (MessageFactoryImpl) SipFactory.getInstance().createMessageFactory();
203 // 设置编码, 防止中文乱码 204 // 设置编码, 防止中文乱码
204 messageFactory.setDefaultContentEncodingCharset(parentPlatform.getCharacterSet()); 205 messageFactory.setDefaultContentEncodingCharset(parentPlatform.getCharacterSet());
205 request = messageFactory.createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, 206 request = messageFactory.createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
206 toHeader, viaHeaders, maxForwards); 207 toHeader, viaHeaders, maxForwards);
207 208
208 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 209 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
209 210
210 - ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); 211 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
211 request.setContent(content, contentTypeHeader); 212 request.setContent(content, contentTypeHeader);
212 return request; 213 return request;
213 } 214 }
@@ -215,54 +216,54 @@ public class SIPRequestHeaderPlarformProvider { @@ -215,54 +216,54 @@ public class SIPRequestHeaderPlarformProvider {
215 public SIPRequest createNotifyRequest(ParentPlatform parentPlatform, String content, SubscribeInfo subscribeInfo) throws PeerUnavailableException, ParseException, InvalidArgumentException { 216 public SIPRequest createNotifyRequest(ParentPlatform parentPlatform, String content, SubscribeInfo subscribeInfo) throws PeerUnavailableException, ParseException, InvalidArgumentException {
216 SIPRequest request = null; 217 SIPRequest request = null;
217 // sipuri 218 // sipuri
218 - SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP()+ ":" + parentPlatform.getServerPort()); 219 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP()+ ":" + parentPlatform.getServerPort());
219 // via 220 // via
220 ArrayList<ViaHeader> viaHeaders = new ArrayList<>(); 221 ArrayList<ViaHeader> viaHeaders = new ArrayList<>();
221 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), parentPlatform.getDevicePort(), 222 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), parentPlatform.getDevicePort(),
222 parentPlatform.getTransport(), SipUtils.getNewViaTag()); 223 parentPlatform.getTransport(), SipUtils.getNewViaTag());
223 viaHeader.setRPort(); 224 viaHeader.setRPort();
224 viaHeaders.add(viaHeader); 225 viaHeaders.add(viaHeader);
225 // from 226 // from
226 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), 227 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(),
227 parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort()); 228 parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort());
228 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
229 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, subscribeInfo.getResponse().getToTag()); 229 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  230 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, subscribeInfo.getResponse().getToTag());
230 // to 231 // to
231 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerGBDomain());  
232 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
233 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress, subscribeInfo.getRequest().getFromTag()); 232 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerGBDomain());
  233 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  234 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, subscribeInfo.getRequest().getFromTag());
234 235
235 // Forwards 236 // Forwards
236 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 237 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
237 // ceq 238 // ceq
238 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.NOTIFY);  
239 - MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipLayer.getSipFactory().createMessageFactory(); 239 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.NOTIFY);
  240 + MessageFactoryImpl messageFactory = (MessageFactoryImpl) SipFactory.getInstance().createMessageFactory();
240 // 设置编码, 防止中文乱码 241 // 设置编码, 防止中文乱码
241 messageFactory.setDefaultContentEncodingCharset("gb2312"); 242 messageFactory.setDefaultContentEncodingCharset("gb2312");
242 243
243 - CallIdHeader callIdHeader = sipLayer.getSipFactory().createHeaderFactory().createCallIdHeader(subscribeInfo.getRequest().getCallIdHeader().getCallId()); 244 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(subscribeInfo.getRequest().getCallIdHeader().getCallId());
244 245
245 request = (SIPRequest) messageFactory.createRequest(requestURI, Request.NOTIFY, callIdHeader, cSeqHeader, fromHeader, 246 request = (SIPRequest) messageFactory.createRequest(requestURI, Request.NOTIFY, callIdHeader, cSeqHeader, fromHeader,
246 toHeader, viaHeaders, maxForwards); 247 toHeader, viaHeaders, maxForwards);
247 248
248 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 249 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
249 250
250 - EventHeader event = sipLayer.getSipFactory().createHeaderFactory().createEventHeader(subscribeInfo.getEventType()); 251 + EventHeader event = SipFactory.getInstance().createHeaderFactory().createEventHeader(subscribeInfo.getEventType());
251 if (subscribeInfo.getEventId() != null) { 252 if (subscribeInfo.getEventId() != null) {
252 event.setEventId(subscribeInfo.getEventId()); 253 event.setEventId(subscribeInfo.getEventId());
253 } 254 }
254 255
255 request.addHeader(event); 256 request.addHeader(event);
256 257
257 - SubscriptionStateHeader active = sipLayer.getSipFactory().createHeaderFactory().createSubscriptionStateHeader("active"); 258 + SubscriptionStateHeader active = SipFactory.getInstance().createHeaderFactory().createSubscriptionStateHeader("active");
258 request.setHeader(active); 259 request.setHeader(active);
259 260
260 String sipAddress = parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort(); 261 String sipAddress = parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort();
261 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory() 262 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory()
262 .createSipURI(parentPlatform.getDeviceGBId(), sipAddress)); 263 .createSipURI(parentPlatform.getDeviceGBId(), sipAddress));
263 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 264 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
264 265
265 - ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); 266 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
266 request.setContent(content, contentTypeHeader); 267 request.setContent(content, contentTypeHeader);
267 return request; 268 return request;
268 } 269 }
@@ -275,42 +276,42 @@ public class SIPRequestHeaderPlarformProvider { @@ -275,42 +276,42 @@ public class SIPRequestHeaderPlarformProvider {
275 276
276 SIPRequest request = null; 277 SIPRequest request = null;
277 // sipuri 278 // sipuri
278 - SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(platform.getServerGBId(), platform.getServerIP()+ ":" + platform.getServerPort()); 279 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(platform.getServerGBId(), platform.getServerIP()+ ":" + platform.getServerPort());
279 // via 280 // via
280 ArrayList<ViaHeader> viaHeaders = new ArrayList<>(); 281 ArrayList<ViaHeader> viaHeaders = new ArrayList<>();
281 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(platform.getDeviceIp(), platform.getDevicePort(), 282 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(platform.getDeviceIp(), platform.getDevicePort(),
282 platform.getTransport(), SipUtils.getNewViaTag()); 283 platform.getTransport(), SipUtils.getNewViaTag());
283 viaHeader.setRPort(); 284 viaHeader.setRPort();
284 viaHeaders.add(viaHeader); 285 viaHeaders.add(viaHeader);
285 // from 286 // from
286 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(platform.getDeviceGBId(), 287 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(platform.getDeviceGBId(),
287 platform.getDeviceIp() + ":" + platform.getDevicePort()); 288 platform.getDeviceIp() + ":" + platform.getDevicePort());
288 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
289 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, sendRtpItem.getToTag()); 289 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  290 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, sendRtpItem.getToTag());
290 // to 291 // to
291 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(platform.getServerGBId(), platform.getServerGBDomain());  
292 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
293 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress, sendRtpItem.getFromTag()); 292 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(platform.getServerGBId(), platform.getServerGBDomain());
  293 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  294 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, sendRtpItem.getFromTag());
294 295
295 // Forwards 296 // Forwards
296 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 297 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
297 // ceq 298 // ceq
298 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);  
299 - MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipLayer.getSipFactory().createMessageFactory(); 299 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);
  300 + MessageFactoryImpl messageFactory = (MessageFactoryImpl) SipFactory.getInstance().createMessageFactory();
300 // 设置编码, 防止中文乱码 301 // 设置编码, 防止中文乱码
301 messageFactory.setDefaultContentEncodingCharset("gb2312"); 302 messageFactory.setDefaultContentEncodingCharset("gb2312");
302 303
303 - CallIdHeader callIdHeader = sipLayer.getSipFactory().createHeaderFactory().createCallIdHeader(sendRtpItem.getCallId()); 304 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(sendRtpItem.getCallId());
304 305
305 request = (SIPRequest) messageFactory.createRequest(requestURI, Request.BYE, callIdHeader, cSeqHeader, fromHeader, 306 request = (SIPRequest) messageFactory.createRequest(requestURI, Request.BYE, callIdHeader, cSeqHeader, fromHeader,
306 toHeader, viaHeaders, maxForwards); 307 toHeader, viaHeaders, maxForwards);
307 308
308 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 309 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
309 310
310 String sipAddress = platform.getDeviceIp() + ":" + platform.getDevicePort(); 311 String sipAddress = platform.getDeviceIp() + ":" + platform.getDevicePort();
311 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory() 312 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory()
312 .createSipURI(platform.getDeviceGBId(), sipAddress)); 313 .createSipURI(platform.getDeviceGBId(), sipAddress));
313 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 314 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
314 315
315 return request; 316 return request;
316 } 317 }
@@ -320,37 +321,37 @@ public class SIPRequestHeaderPlarformProvider { @@ -320,37 +321,37 @@ public class SIPRequestHeaderPlarformProvider {
320 //请求行 321 //请求行
321 String platformHostAddress = platform.getServerIP() + ":" + platform.getServerPort(); 322 String platformHostAddress = platform.getServerIP() + ":" + platform.getServerPort();
322 String localHostAddress = sipLayer.getLocalIp(platform.getDeviceIp())+":"+ platform.getDevicePort(); 323 String localHostAddress = sipLayer.getLocalIp(platform.getDeviceIp())+":"+ platform.getDevicePort();
323 - SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, platformHostAddress); 324 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, platformHostAddress);
324 //via 325 //via
325 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 326 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
326 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getDevicePort(), platform.getTransport(), viaTag); 327 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getDevicePort(), platform.getTransport(), viaTag);
327 viaHeader.setRPort(); 328 viaHeader.setRPort();
328 viaHeaders.add(viaHeader); 329 viaHeaders.add(viaHeader);
329 330
330 //from 331 //from
331 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(platform.getDeviceGBId(), sipConfig.getDomain());  
332 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
333 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack 332 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(platform.getDeviceGBId(), sipConfig.getDomain());
  333 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  334 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
334 //to 335 //to
335 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, platformHostAddress);  
336 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
337 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,null); 336 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, platformHostAddress);
  337 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  338 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);
338 339
339 //Forwards 340 //Forwards
340 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 341 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
341 342
342 //ceq 343 //ceq
343 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);  
344 - request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); 344 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);
  345 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
345 346
346 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 347 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
347 348
348 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(),localHostAddress));  
349 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 349 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),localHostAddress));
  350 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
350 // Subject 351 // Subject
351 - SubjectHeader subjectHeader = sipLayer.getSipFactory().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); 352 + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
352 request.addHeader(subjectHeader); 353 request.addHeader(subjectHeader);
353 - ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); 354 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
354 request.setContent(content, contentTypeHeader); 355 request.setContent(content, contentTypeHeader);
355 return request; 356 return request;
356 } 357 }
@@ -358,35 +359,35 @@ public class SIPRequestHeaderPlarformProvider { @@ -358,35 +359,35 @@ public class SIPRequestHeaderPlarformProvider {
358 public Request createByteRequest(ParentPlatform platform, String channelId, SipTransactionInfo transactionInfo) throws PeerUnavailableException, ParseException, InvalidArgumentException { 359 public Request createByteRequest(ParentPlatform platform, String channelId, SipTransactionInfo transactionInfo) throws PeerUnavailableException, ParseException, InvalidArgumentException {
359 String deviceHostAddress = platform.getDeviceIp() + ":" + platform.getDevicePort(); 360 String deviceHostAddress = platform.getDeviceIp() + ":" + platform.getDevicePort();
360 Request request = null; 361 Request request = null;
361 - SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, deviceHostAddress); 362 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, deviceHostAddress);
362 363
363 // via 364 // via
364 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 365 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
365 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getDevicePort(), platform.getTransport(), SipUtils.getNewViaTag()); 366 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getDevicePort(), platform.getTransport(), SipUtils.getNewViaTag());
366 viaHeaders.add(viaHeader); 367 viaHeaders.add(viaHeader);
367 //from 368 //from
368 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());  
369 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
370 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.isAsSender()?transactionInfo.getFromTag():transactionInfo.getToTag()); 369 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  370 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  371 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.isAsSender()?transactionInfo.getFromTag():transactionInfo.getToTag());
371 //to 372 //to
372 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, deviceHostAddress);  
373 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
374 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,transactionInfo.isAsSender()?transactionInfo.getToTag():transactionInfo.getFromTag()); 373 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, deviceHostAddress);
  374 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  375 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,transactionInfo.isAsSender()?transactionInfo.getToTag():transactionInfo.getFromTag());
375 376
376 //Forwards 377 //Forwards
377 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 378 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
378 379
379 //ceq 380 //ceq
380 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);  
381 - CallIdHeader callIdHeader = sipLayer.getSipFactory().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());  
382 - request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); 381 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);
  382 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  383 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
383 384
384 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 385 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
385 386
386 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(platform.getDeviceIp())+":"+ platform.getDevicePort()));  
387 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 387 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(platform.getDeviceIp())+":"+ platform.getDevicePort()));
  388 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
388 389
389 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 390 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
390 391
391 return request; 392 return request;
392 } 393 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
@@ -16,6 +16,7 @@ import org.springframework.stereotype.Component; @@ -16,6 +16,7 @@ import org.springframework.stereotype.Component;
16 import javax.sip.InvalidArgumentException; 16 import javax.sip.InvalidArgumentException;
17 import javax.sip.PeerUnavailableException; 17 import javax.sip.PeerUnavailableException;
18 import javax.sip.SipException; 18 import javax.sip.SipException;
  19 +import javax.sip.SipFactory;
19 import javax.sip.address.Address; 20 import javax.sip.address.Address;
20 import javax.sip.address.SipURI; 21 import javax.sip.address.SipURI;
21 import javax.sip.header.*; 22 import javax.sip.header.*;
@@ -49,32 +50,32 @@ public class SIPRequestHeaderProvider { @@ -49,32 +50,32 @@ public class SIPRequestHeaderProvider {
49 public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { 50 public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
50 Request request = null; 51 Request request = null;
51 // sipuri 52 // sipuri
52 - SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); 53 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
53 // via 54 // via
54 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 55 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
55 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); 56 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
56 viaHeader.setRPort(); 57 viaHeader.setRPort();
57 viaHeaders.add(viaHeader); 58 viaHeaders.add(viaHeader);
58 // from 59 // from
59 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
60 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
61 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag); 60 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  61 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  62 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag);
62 // to 63 // to
63 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
64 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
65 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress, toTag); 64 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  65 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  66 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag);
66 67
67 // Forwards 68 // Forwards
68 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 69 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
69 // ceq 70 // ceq
70 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE); 71 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);
71 72
72 - request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, 73 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
73 toHeader, viaHeaders, maxForwards); 74 toHeader, viaHeaders, maxForwards);
74 75
75 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 76 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
76 77
77 - ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); 78 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
78 request.setContent(content, contentTypeHeader); 79 request.setContent(content, contentTypeHeader);
79 return request; 80 return request;
80 } 81 }
@@ -82,39 +83,39 @@ public class SIPRequestHeaderProvider { @@ -82,39 +83,39 @@ public class SIPRequestHeaderProvider {
82 public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { 83 public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
83 Request request = null; 84 Request request = null;
84 //请求行 85 //请求行
85 - SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress()); 86 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
86 //via 87 //via
87 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 88 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
88 - HeaderFactory headerFactory = sipLayer.getSipFactory().createHeaderFactory();  
89 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); 89 + HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory();
  90 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
90 viaHeader.setRPort(); 91 viaHeader.setRPort();
91 viaHeaders.add(viaHeader); 92 viaHeaders.add(viaHeader);
92 93
93 //from 94 //from
94 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
95 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
96 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack 95 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  96 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  97 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
97 //to 98 //to
98 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
99 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
100 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,null); 99 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  100 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  101 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);
101 102
102 //Forwards 103 //Forwards
103 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 104 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
104 105
105 //ceq 106 //ceq
106 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);  
107 - request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); 107 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);
  108 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
108 109
109 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 110 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
110 111
111 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
112 - // Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));  
113 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 112 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  113 + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
  114 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
114 // Subject 115 // Subject
115 - SubjectHeader subjectHeader = sipLayer.getSipFactory().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); 116 + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
116 request.addHeader(subjectHeader); 117 request.addHeader(subjectHeader);
117 - ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); 118 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
118 request.setContent(content, contentTypeHeader); 119 request.setContent(content, contentTypeHeader);
119 return request; 120 return request;
120 } 121 }
@@ -122,69 +123,74 @@ public class SIPRequestHeaderProvider { @@ -122,69 +123,74 @@ public class SIPRequestHeaderProvider {
122 public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException { 123 public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {
123 Request request = null; 124 Request request = null;
124 //请求行 125 //请求行
125 - SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress()); 126 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
126 // via 127 // via
127 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 128 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
128 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag); 129 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
129 viaHeader.setRPort(); 130 viaHeader.setRPort();
130 viaHeaders.add(viaHeader); 131 viaHeaders.add(viaHeader);
131 //from 132 //from
132 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
133 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
134 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack 133 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  134 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  135 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
135 //to 136 //to
136 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
137 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
138 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,null); 137 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  138 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  139 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);
139 140
140 //Forwards 141 //Forwards
141 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 142 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
142 143
143 //ceq 144 //ceq
144 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);  
145 - request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); 145 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);
  146 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
146 147
147 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
148 - // Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));  
149 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 148 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  149 + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
  150 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
150 151
151 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 152 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
152 153
153 // Subject 154 // Subject
154 - SubjectHeader subjectHeader = sipLayer.getSipFactory().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0)); 155 + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
155 request.addHeader(subjectHeader); 156 request.addHeader(subjectHeader);
156 157
157 - ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); 158 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
158 request.setContent(content, contentTypeHeader); 159 request.setContent(content, contentTypeHeader);
159 return request; 160 return request;
160 } 161 }
161 162
162 public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException { 163 public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException {
163 Request request = null; 164 Request request = null;
164 - SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
165 - 165 + //请求行
  166 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
166 // via 167 // via
167 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 168 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
168 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); 169 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
169 viaHeaders.add(viaHeader); 170 viaHeaders.add(viaHeader);
170 //from 171 //from
171 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());  
172 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
173 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, !transactionInfo.isAsSender()? transactionInfo.getToTag():transactionInfo.getFromTag()); 172 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  173 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  174 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
174 //to 175 //to
175 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId,device.getHostAddress());  
176 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
177 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress, !transactionInfo.isAsSender()? transactionInfo.getToTag(): transactionInfo.getFromTag()); 176 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());
  177 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  178 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());
178 179
179 //Forwards 180 //Forwards
180 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 181 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
181 182
182 //ceq 183 //ceq
183 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);  
184 - CallIdHeader callIdHeader = sipLayer.getSipFactory().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());  
185 - request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); 184 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);
  185 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  186 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  187 +
  188 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
186 189
187 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 190 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  191 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  192 +
  193 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
188 194
189 return request; 195 return request;
190 } 196 }
@@ -192,50 +198,50 @@ public class SIPRequestHeaderProvider { @@ -192,50 +198,50 @@ public class SIPRequestHeaderProvider {
192 public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { 198 public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
193 Request request = null; 199 Request request = null;
194 // sipuri 200 // sipuri
195 - SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); 201 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
196 // via 202 // via
197 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 203 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
198 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), 204 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(),
199 device.getTransport(), SipUtils.getNewViaTag()); 205 device.getTransport(), SipUtils.getNewViaTag());
200 viaHeader.setRPort(); 206 viaHeader.setRPort();
201 viaHeaders.add(viaHeader); 207 viaHeaders.add(viaHeader);
202 // from 208 // from
203 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
204 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
205 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag()); 209 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  210 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  211 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag());
206 // to 212 // to
207 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
208 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
209 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag()); 213 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  214 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  215 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag());
210 216
211 // Forwards 217 // Forwards
212 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 218 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
213 219
214 // ceq 220 // ceq
215 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE); 221 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE);
216 222
217 - request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader, 223 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader,
218 toHeader, viaHeaders, maxForwards); 224 toHeader, viaHeaders, maxForwards);
219 225
220 226
221 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
222 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 227 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  228 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
223 229
224 // Expires 230 // Expires
225 - ExpiresHeader expireHeader = sipLayer.getSipFactory().createHeaderFactory().createExpiresHeader(expires); 231 + ExpiresHeader expireHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires);
226 request.addHeader(expireHeader); 232 request.addHeader(expireHeader);
227 233
228 // Event 234 // Event
229 - EventHeader eventHeader = sipLayer.getSipFactory().createHeaderFactory().createEventHeader(event); 235 + EventHeader eventHeader = SipFactory.getInstance().createHeaderFactory().createEventHeader(event);
230 236
231 int random = (int) Math.floor(Math.random() * 10000); 237 int random = (int) Math.floor(Math.random() * 10000);
232 eventHeader.setEventId(random + ""); 238 eventHeader.setEventId(random + "");
233 request.addHeader(eventHeader); 239 request.addHeader(eventHeader);
234 240
235 - ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); 241 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
236 request.setContent(content, contentTypeHeader); 242 request.setContent(content, contentTypeHeader);
237 243
238 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 244 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
239 245
240 return request; 246 return request;
241 } 247 }
@@ -247,37 +253,37 @@ public class SIPRequestHeaderProvider { @@ -247,37 +253,37 @@ public class SIPRequestHeaderProvider {
247 } 253 }
248 SIPRequest request = null; 254 SIPRequest request = null;
249 //请求行 255 //请求行
250 - SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress()); 256 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
251 // via 257 // via
252 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 258 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
253 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); 259 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
254 viaHeaders.add(viaHeader); 260 viaHeaders.add(viaHeader);
255 //from 261 //from
256 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());  
257 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
258 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); 262 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  263 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  264 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
259 //to 265 //to
260 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId,device.getHostAddress());  
261 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
262 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); 266 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());
  267 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  268 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());
263 269
264 //Forwards 270 //Forwards
265 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 271 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
266 272
267 //ceq 273 //ceq
268 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO);  
269 - CallIdHeader callIdHeader = sipLayer.getSipFactory().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());  
270 - request = (SIPRequest)sipLayer.getSipFactory().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); 274 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO);
  275 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  276 + request = (SIPRequest)SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
271 277
272 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 278 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
273 279
274 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
275 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 280 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  281 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
276 282
277 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 283 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
278 284
279 if (content != null) { 285 if (content != null) {
280 - ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("Application", 286 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application",
281 "MANSRTSP"); 287 "MANSRTSP");
282 request.setContent(content, contentTypeHeader); 288 request.setContent(content, contentTypeHeader);
283 } 289 }
@@ -289,56 +295,55 @@ public class SIPRequestHeaderProvider { @@ -289,56 +295,55 @@ public class SIPRequestHeaderProvider {
289 295
290 // via 296 // via
291 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 297 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
292 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag()); 298 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag());
293 viaHeaders.add(viaHeader); 299 viaHeaders.add(viaHeader);
294 300
295 //Forwards 301 //Forwards
296 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 302 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
297 303
298 //ceq 304 //ceq
299 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK); 305 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK);
300 306
301 - Request request = sipLayer.getSipFactory().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards); 307 + Request request = SipFactory.getInstance().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards);
302 308
303 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 309 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
304 310
305 - Address concatAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort()));  
306 - request.addHeader(sipLayer.getSipFactory().createHeaderFactory().createContactHeader(concatAddress)); 311 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort()));
  312 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
307 313
308 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 314 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
309 315
310 return request; 316 return request;
311 } 317 }
312 -  
313 public Request createBroadcastMessageRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { 318 public Request createBroadcastMessageRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
314 Request request = null; 319 Request request = null;
315 // sipuri 320 // sipuri
316 - SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress()); 321 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
317 // via 322 // via
318 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 323 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
319 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag); 324 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
320 viaHeader.setRPort(); 325 viaHeader.setRPort();
321 viaHeaders.add(viaHeader); 326 viaHeaders.add(viaHeader);
322 // from 327 // from
323 - SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
324 - Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);  
325 - FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag); 328 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  329 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  330 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag);
326 // to 331 // to
327 - SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
328 - Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);  
329 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress, toTag); 332 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  333 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  334 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag);
330 335
331 // Forwards 336 // Forwards
332 - MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 337 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
333 // ceq 338 // ceq
334 - CSeqHeader cSeqHeader = sipLayer.getSipFactory().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE); 339 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);
335 340
336 - ContentTypeHeader contentTypeHeader = sipLayer.getSipFactory().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); 341 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
337 342
338 - request = sipLayer.getSipFactory().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, 343 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
339 toHeader, viaHeaders, maxForwards, contentTypeHeader, content); 344 toHeader, viaHeaders, maxForwards, contentTypeHeader, content);
340 345
341 - request.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil)); 346 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
342 347
343 return request; 348 return request;
344 } 349 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
1 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.common.StreamInfo; 5 import com.genersoft.iot.vmp.common.StreamInfo;
5 import com.genersoft.iot.vmp.conf.SipConfig; 6 import com.genersoft.iot.vmp.conf.SipConfig;
6 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
@@ -36,6 +37,7 @@ import org.springframework.util.ObjectUtils; @@ -36,6 +37,7 @@ import org.springframework.util.ObjectUtils;
36 import javax.sip.InvalidArgumentException; 37 import javax.sip.InvalidArgumentException;
37 import javax.sip.ResponseEvent; 38 import javax.sip.ResponseEvent;
38 import javax.sip.SipException; 39 import javax.sip.SipException;
  40 +import javax.sip.SipFactory;
39 import javax.sip.header.CallIdHeader; 41 import javax.sip.header.CallIdHeader;
40 import javax.sip.message.Request; 42 import javax.sip.message.Request;
41 import java.text.ParseException; 43 import java.text.ParseException;
@@ -358,7 +360,7 @@ public class SIPCommander implements ISIPCommander { @@ -358,7 +360,7 @@ public class SIPCommander implements ISIPCommander {
358 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 360 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
359 ResponseEvent responseEvent = (ResponseEvent) e.event; 361 ResponseEvent responseEvent = (ResponseEvent) e.event;
360 SIPResponse response = (SIPResponse) responseEvent.getResponse(); 362 SIPResponse response = (SIPResponse) responseEvent.getResponse();
361 - streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play); 363 + streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAY);
362 okEvent.response(e); 364 okEvent.response(e);
363 }); 365 });
364 } 366 }
@@ -373,11 +375,11 @@ public class SIPCommander implements ISIPCommander { @@ -373,11 +375,11 @@ public class SIPCommander implements ISIPCommander {
373 */ 375 */
374 @Override 376 @Override
375 public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 377 public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
376 - String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, 378 + String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent,
377 SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { 379 SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
378 380
379 381
380 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getSdpIp(), mediaServerItem.getIp(), ssrcInfo.getPort()); 382 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
381 String sdpIp; 383 String sdpIp;
382 if (!ObjectUtils.isEmpty(device.getSdpIp())) { 384 if (!ObjectUtils.isEmpty(device.getSdpIp())) {
383 sdpIp = device.getSdpIp(); 385 sdpIp = device.getSdpIp();
@@ -450,8 +452,7 @@ public class SIPCommander implements ISIPCommander { @@ -450,8 +452,7 @@ public class SIPCommander implements ISIPCommander {
450 // 添加订阅 452 // 添加订阅
451 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { 453 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
452 if (hookEvent != null) { 454 if (hookEvent != null) {
453 - InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), "rtp", ssrcInfo.getStream());  
454 - hookEvent.call(inviteStreamInfo); 455 + hookEvent.response(mediaServerItemInUse, json);
455 } 456 }
456 subscribe.removeSubscribe(hookSubscribe); 457 subscribe.removeSubscribe(hookSubscribe);
457 }); 458 });
@@ -460,12 +461,9 @@ public class SIPCommander implements ISIPCommander { @@ -460,12 +461,9 @@ public class SIPCommander implements ISIPCommander {
460 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { 461 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
461 ResponseEvent responseEvent = (ResponseEvent) event.event; 462 ResponseEvent responseEvent = (ResponseEvent) event.event;
462 SIPResponse response = (SIPResponse) responseEvent.getResponse(); 463 SIPResponse response = (SIPResponse) responseEvent.getResponse();
463 - streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.playback); 464 + streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK);
464 okEvent.response(event); 465 okEvent.response(event);
465 }); 466 });
466 - if (inviteStreamCallback != null) {  
467 - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), "rtp", ssrcInfo.getStream()));  
468 - }  
469 } 467 }
470 468
471 /** 469 /**
@@ -480,10 +478,10 @@ public class SIPCommander implements ISIPCommander { @@ -480,10 +478,10 @@ public class SIPCommander implements ISIPCommander {
480 @Override 478 @Override
481 public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 479 public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
482 String startTime, String endTime, int downloadSpeed, 480 String startTime, String endTime, int downloadSpeed,
483 - InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, 481 + ZlmHttpHookSubscribe.Event hookEvent,
484 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { 482 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
485 483
486 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getSdpIp(), mediaServerItem.getIp(), ssrcInfo.getPort()); 484 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
487 String sdpIp; 485 String sdpIp;
488 if (!ObjectUtils.isEmpty(device.getSdpIp())) { 486 if (!ObjectUtils.isEmpty(device.getSdpIp())) {
489 sdpIp = device.getSdpIp(); 487 sdpIp = device.getSdpIp();
@@ -551,13 +549,13 @@ public class SIPCommander implements ISIPCommander { @@ -551,13 +549,13 @@ public class SIPCommander implements ISIPCommander {
551 549
552 content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc 550 content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
553 logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc()); 551 logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());
554 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); 552 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
555 // 添加订阅 553 // 添加订阅
556 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); 554 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
557 - String callId=newCallIdHeader.getCallId(); 555 + String callId= newCallIdHeader.getCallId();
558 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { 556 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
559 logger.debug("sipc 添加订阅===callId {}",callId); 557 logger.debug("sipc 添加订阅===callId {}",callId);
560 - hookEvent.call(new InviteStreamInfo(mediaServerItem, json,callId, "rtp", ssrcInfo.getStream())); 558 + hookEvent.response(mediaServerItemInUse, json);
561 subscribe.removeSubscribe(hookSubscribe); 559 subscribe.removeSubscribe(hookSubscribe);
562 hookSubscribe.getContent().put("regist", false); 560 hookSubscribe.getContent().put("regist", false);
563 hookSubscribe.getContent().put("schema", "rtsp"); 561 hookSubscribe.getContent().put("schema", "rtsp");
@@ -566,7 +564,7 @@ public class SIPCommander implements ISIPCommander { @@ -566,7 +564,7 @@ public class SIPCommander implements ISIPCommander {
566 (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> { 564 (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> {
567 logger.info("[录像]下载结束, 发送BYE"); 565 logger.info("[录像]下载结束, 发送BYE");
568 try { 566 try {
569 - streamByeCmd(device, channelId, ssrcInfo.getStream(),callId); 567 + streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);
570 } catch (InvalidArgumentException | ParseException | SipException | 568 } catch (InvalidArgumentException | ParseException | SipException |
571 SsrcTransactionNotFoundException e) { 569 SsrcTransactionNotFoundException e) {
572 logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); 570 logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage());
@@ -575,9 +573,6 @@ public class SIPCommander implements ISIPCommander { @@ -575,9 +573,6 @@ public class SIPCommander implements ISIPCommander {
575 }); 573 });
576 574
577 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc()); 575 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
578 - if (inviteStreamCallback != null) {  
579 - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null,callId, "rtp", ssrcInfo.getStream()));  
580 - }  
581 576
582 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { 577 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
583 ResponseEvent responseEvent = (ResponseEvent) event.event; 578 ResponseEvent responseEvent = (ResponseEvent) event.event;
@@ -588,9 +583,7 @@ public class SIPCommander implements ISIPCommander { @@ -588,9 +583,7 @@ public class SIPCommander implements ISIPCommander {
588 if (ssrcIndex >= 0) { 583 if (ssrcIndex >= 0) {
589 ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); 584 ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
590 } 585 }
591 - logger.debug("接收到的下载响应ssrc====>{}",ssrcInfo.getSsrc());  
592 - logger.debug("接收到的下载响应ssrc====>{}",ssrc);  
593 - streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download); 586 + streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);
594 okEvent.response(event); 587 okEvent.response(event);
595 }); 588 });
596 } 589 }
@@ -654,7 +647,7 @@ public class SIPCommander implements ISIPCommander { @@ -654,7 +647,7 @@ public class SIPCommander implements ISIPCommander {
654 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 647 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
655 ResponseEvent responseEvent = (ResponseEvent) e.event; 648 ResponseEvent responseEvent = (ResponseEvent) e.event;
656 SIPResponse response = (SIPResponse) responseEvent.getResponse(); 649 SIPResponse response = (SIPResponse) responseEvent.getResponse();
657 - streamSession.put(device.getDeviceId(), channelId, "talk", stream, sendRtpItem.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.talk); 650 + streamSession.put(device.getDeviceId(), channelId, "talk", stream, sendRtpItem.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.TALK);
658 okEvent.response(e); 651 okEvent.response(e);
659 }); 652 });
660 } 653 }
@@ -1247,7 +1240,7 @@ public class SIPCommander implements ISIPCommander { @@ -1247,7 +1240,7 @@ public class SIPCommander implements ISIPCommander {
1247 CallIdHeader callIdHeader; 1240 CallIdHeader callIdHeader;
1248 1241
1249 if (requestOld != null) { 1242 if (requestOld != null) {
1250 - callIdHeader = sipLayer.getSipFactory().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); 1243 + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
1251 } else { 1244 } else {
1252 callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); 1245 callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());
1253 } 1246 }
@@ -1322,7 +1315,7 @@ public class SIPCommander implements ISIPCommander { @@ -1322,7 +1315,7 @@ public class SIPCommander implements ISIPCommander {
1322 CallIdHeader callIdHeader; 1315 CallIdHeader callIdHeader;
1323 1316
1324 if (requestOld != null) { 1317 if (requestOld != null) {
1325 - callIdHeader = sipLayer.getSipFactory().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); 1318 + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
1326 } else { 1319 } else {
1327 callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); 1320 callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());
1328 } 1321 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
2 2
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.alibaba.fastjson2.JSONObject; 4 import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.InviteSessionType;
5 import com.genersoft.iot.vmp.conf.DynamicTask; 6 import com.genersoft.iot.vmp.conf.DynamicTask;
6 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 8 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
@@ -39,6 +40,7 @@ import org.springframework.util.ObjectUtils; @@ -39,6 +40,7 @@ import org.springframework.util.ObjectUtils;
39 import javax.sip.InvalidArgumentException; 40 import javax.sip.InvalidArgumentException;
40 import javax.sip.ResponseEvent; 41 import javax.sip.ResponseEvent;
41 import javax.sip.SipException; 42 import javax.sip.SipException;
  43 +import javax.sip.SipFactory;
42 import javax.sip.header.CallIdHeader; 44 import javax.sip.header.CallIdHeader;
43 import javax.sip.header.WWWAuthenticateHeader; 45 import javax.sip.header.WWWAuthenticateHeader;
44 import javax.sip.message.Request; 46 import javax.sip.message.Request;
@@ -518,7 +520,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -518,7 +520,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
518 private void sendNotify(ParentPlatform parentPlatform, String catalogXmlContent, 520 private void sendNotify(ParentPlatform parentPlatform, String catalogXmlContent,
519 SubscribeInfo subscribeInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent ) 521 SubscribeInfo subscribeInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent )
520 throws SipException, ParseException, InvalidArgumentException { 522 throws SipException, ParseException, InvalidArgumentException {
521 - MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipLayer.getSipFactory().createMessageFactory(); 523 + MessageFactoryImpl messageFactory = (MessageFactoryImpl) SipFactory.getInstance().createMessageFactory();
522 String characterSet = parentPlatform.getCharacterSet(); 524 String characterSet = parentPlatform.getCharacterSet();
523 // 设置编码, 防止中文乱码 525 // 设置编码, 防止中文乱码
524 messageFactory.setDefaultContentEncodingCharset(characterSet); 526 messageFactory.setDefaultContentEncodingCharset(characterSet);
@@ -854,7 +856,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -854,7 +856,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
854 }), e -> { 856 }), e -> {
855 ResponseEvent responseEvent = (ResponseEvent) e.event; 857 ResponseEvent responseEvent = (ResponseEvent) e.event;
856 SIPResponse response = (SIPResponse) responseEvent.getResponse(); 858 SIPResponse response = (SIPResponse) responseEvent.getResponse();
857 - streamSession.put(platform.getServerGBId(), channelId, callIdHeader.getCallId(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.broadcast); 859 + streamSession.put(platform.getServerGBId(), channelId, callIdHeader.getCallId(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.BROADCAST);
858 okEvent.response(e); 860 okEvent.response(e);
859 }); 861 });
860 } 862 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2
3 -import com.genersoft.iot.vmp.common.StreamInfo; 3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 5 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 import com.genersoft.iot.vmp.gb28181.bean.*; 6 import com.genersoft.iot.vmp.gb28181.bean.*;
6 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; 7 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
  8 +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
7 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 9 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
8 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 10 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
9 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
@@ -13,6 +15,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP @@ -13,6 +15,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP
13 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 15 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
14 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 16 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
15 import com.genersoft.iot.vmp.service.IDeviceService; 17 import com.genersoft.iot.vmp.service.IDeviceService;
  18 +import com.genersoft.iot.vmp.service.IInviteStreamService;
16 import com.genersoft.iot.vmp.service.IMediaServerService; 19 import com.genersoft.iot.vmp.service.IMediaServerService;
17 import com.genersoft.iot.vmp.service.IPlayService; 20 import com.genersoft.iot.vmp.service.IPlayService;
18 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 21 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
@@ -29,6 +32,7 @@ import javax.sip.InvalidArgumentException; @@ -29,6 +32,7 @@ import javax.sip.InvalidArgumentException;
29 import javax.sip.RequestEvent; 32 import javax.sip.RequestEvent;
30 import javax.sip.SipException; 33 import javax.sip.SipException;
31 import javax.sip.address.SipURI; 34 import javax.sip.address.SipURI;
  35 +import javax.sip.header.CallIdHeader;
32 import javax.sip.header.FromHeader; 36 import javax.sip.header.FromHeader;
33 import javax.sip.header.HeaderAddress; 37 import javax.sip.header.HeaderAddress;
34 import javax.sip.header.ToHeader; 38 import javax.sip.header.ToHeader;
@@ -57,6 +61,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -57,6 +61,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
57 private IRedisCatchStorage redisCatchStorage; 61 private IRedisCatchStorage redisCatchStorage;
58 62
59 @Autowired 63 @Autowired
  64 + private IInviteStreamService inviteStreamService;
  65 +
  66 + @Autowired
60 private IDeviceService deviceService; 67 private IDeviceService deviceService;
61 68
62 @Autowired 69 @Autowired
@@ -69,6 +76,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -69,6 +76,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
69 private ZLMRTPServerFactory zlmrtpServerFactory; 76 private ZLMRTPServerFactory zlmrtpServerFactory;
70 77
71 @Autowired 78 @Autowired
  79 + private SSRCFactory ssrcFactory;
  80 +
  81 + @Autowired
72 private IMediaServerService mediaServerService; 82 private IMediaServerService mediaServerService;
73 83
74 @Autowired 84 @Autowired
@@ -100,92 +110,89 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -100,92 +110,89 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
100 } catch (SipException | InvalidArgumentException | ParseException e) { 110 } catch (SipException | InvalidArgumentException | ParseException e) {
101 logger.error("[回复BYE信息失败],{}", e.getMessage()); 111 logger.error("[回复BYE信息失败],{}", e.getMessage());
102 } 112 }
103 -  
104 - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, request.getCallIdHeader().getCallId());  
105 -  
106 - if (sendRtpItem != null){  
107 - logger.info("[收到bye] {}/{}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId());  
108 - String streamId = sendRtpItem.getStream();  
109 - MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());  
110 - if (mediaServerItem == null) {  
111 - return;  
112 - }  
113 -  
114 - Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItem, sendRtpItem.getApp(), streamId);  
115 - if (!ready) {  
116 - logger.info("[收到bye] 发现流{}/{}已经结束,不需处理", sendRtpItem.getApp(), sendRtpItem.getStream());  
117 - return;  
118 - }  
119 - Map<String, Object> param = new HashMap<>();  
120 - param.put("vhost","__defaultVhost__");  
121 - param.put("app",sendRtpItem.getApp());  
122 - param.put("stream",streamId);  
123 - param.put("ssrc",sendRtpItem.getSsrc());  
124 - logger.info("[收到bye] 停止推流:{}", streamId);  
125 - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());  
126 - redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), request.getCallIdHeader().getCallId(), null);  
127 - zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);  
128 -  
129 - int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);  
130 - if (totalReaderCount <= 0) {  
131 - logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId);  
132 - if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) {  
133 - Device device = deviceService.getDevice(sendRtpItem.getDeviceId());  
134 - if (device == null) {  
135 - logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId); 113 + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
  114 + String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
  115 + String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
  116 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId, null, callIdHeader.getCallId());
  117 + logger.info("[收到bye] {}/{}", platformGbId, channelId);
  118 + if (sendRtpItem != null){
  119 + String streamId = sendRtpItem.getStream();
  120 + Map<String, Object> param = new HashMap<>();
  121 + param.put("vhost","__defaultVhost__");
  122 + param.put("app",sendRtpItem.getApp());
  123 + param.put("stream",streamId);
  124 + param.put("ssrc",sendRtpItem.getSsrc());
  125 + logger.info("[收到bye] 停止向上级推流:{}", streamId);
  126 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  127 + redisCatchStorage.deleteSendRTPServer(platformGbId, channelId, callIdHeader.getCallId(), null);
  128 + ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
  129 + zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
  130 + int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);
  131 + if (totalReaderCount <= 0) {
  132 + logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId);
  133 + if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) {
  134 + Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
  135 + if (device == null) {
  136 + logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId);
  137 + }
  138 + try {
  139 + logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), channelId);
  140 + cmder.streamByeCmd(device, channelId, streamId, null);
  141 + } catch (InvalidArgumentException | ParseException | SipException |
  142 + SsrcTransactionNotFoundException e) {
  143 + logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage());
  144 + }
136 } 145 }
137 - try {  
138 - logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());  
139 - cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null);  
140 - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {  
141 - logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); 146 + if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {
  147 + MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
  148 + sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
  149 + sendRtpItem.getPlatformId(), null, null, sendRtpItem.getMediaServerId());
  150 + redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);
142 } 151 }
143 } 152 }
144 -  
145 - if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {  
146 - MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,  
147 - sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),  
148 - sendRtpItem.getPlatformId(), null, null, sendRtpItem.getMediaServerId());  
149 - redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);  
150 - }  
151 } 153 }
  154 + // 可能是设备主动停止
  155 + Device device = storager.queryVideoDeviceByChannelId(platformGbId);
  156 + if (device != null) {
  157 + storager.stopPlay(device.getDeviceId(), channelId);
  158 + SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);
  159 + if (ssrcTransactionForPlay != null){
  160 + if (ssrcTransactionForPlay.getCallId().equals(callIdHeader.getCallId())){
  161 + // 释放ssrc
  162 + MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlay.getMediaServerId());
  163 + if (mediaServerItem != null) {
  164 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlay.getSsrc());
  165 + }
  166 + streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream());
  167 + }
  168 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
152 169
153 - playService.stopAudioBroadcast(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());  
154 - }  
155 -  
156 - String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();  
157 - String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();  
158 -  
159 - // 可能是设备主动停止  
160 - Device device = storager.queryVideoDeviceByChannelId(platformGbId);  
161 - if (device != null) {  
162 - storager.stopPlay(device.getDeviceId(), channelId);  
163 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);  
164 - if (streamInfo != null) {  
165 - redisCatchStorage.stopPlay(streamInfo);  
166 - mediaServerService.closeRTPServer(streamInfo.getMediaServerId(), streamInfo.getStream());  
167 - }  
168 - SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);  
169 - if (ssrcTransactionForPlay != null){  
170 - if (ssrcTransactionForPlay.getCallId().equals(request.getCallIdHeader().getCallId())){ 170 + if (inviteInfo != null) {
  171 + inviteStreamService.removeInviteInfo(inviteInfo);
  172 + if (inviteInfo.getStreamInfo() != null) {
  173 + mediaServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServerId(), inviteInfo.getStream());
  174 + }
  175 + }
  176 + }
  177 + SsrcTransaction ssrcTransactionForPlayBack = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callIdHeader.getCallId(), null);
  178 + if (ssrcTransactionForPlayBack != null) {
171 // 释放ssrc 179 // 释放ssrc
172 - MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlay.getMediaServerId()); 180 + MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlayBack.getMediaServerId());
173 if (mediaServerItem != null) { 181 if (mediaServerItem != null) {
174 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlay.getSsrc()); 182 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlayBack.getSsrc());
  183 + }
  184 + streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlayBack.getStream());
  185 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, device.getDeviceId(), channelId);
  186 +
  187 + if (inviteInfo != null) {
  188 + inviteStreamService.removeInviteInfo(inviteInfo);
  189 + if (inviteInfo.getStreamInfo() != null) {
  190 + mediaServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServerId(), inviteInfo.getStream());
  191 + }
175 } 192 }
176 - streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream());  
177 - }  
178 - }  
179 - SsrcTransaction ssrcTransactionForPlayBack = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, request.getCallIdHeader().getCallId(), null);  
180 - if (ssrcTransactionForPlayBack != null) {  
181 - // 释放ssrc  
182 - MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlayBack.getMediaServerId());  
183 - if (mediaServerItem != null) {  
184 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlayBack.getSsrc());  
185 } 193 }
186 - streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlayBack.getStream());  
187 } 194 }
188 - } 195 +
189 SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, request.getCallIdHeader().getCallId(), null); 196 SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, request.getCallIdHeader().getCallId(), null);
190 if (ssrcTransaction != null) { 197 if (ssrcTransaction != null) {
191 // 释放ssrc 198 // 释放ssrc
@@ -203,7 +210,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -203,7 +210,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
203 // break; 210 // break;
204 // case download: 211 // case download:
205 // break; 212 // break;
206 - case broadcast: 213 + case BROADCAST:
207 String channelId1 = ssrcTransaction.getChannelId(); 214 String channelId1 = ssrcTransaction.getChannelId();
208 215
209 Device deviceFromTransaction = storager.queryVideoDevice(ssrcTransaction.getDeviceId()); 216 Device deviceFromTransaction = storager.queryVideoDevice(ssrcTransaction.getDeviceId());
@@ -255,7 +262,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -255,7 +262,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
255 List<SsrcTransaction> ssrcTransactions = streamSession.getSsrcTransactionForAll(null, channelId1, null, null); 262 List<SsrcTransaction> ssrcTransactions = streamSession.getSsrcTransactionForAll(null, channelId1, null, null);
256 if (ssrcTransactions.size() > 0) { 263 if (ssrcTransactions.size() > 0) {
257 for (SsrcTransaction transaction : ssrcTransactions) { 264 for (SsrcTransaction transaction : ssrcTransactions) {
258 - if (transaction.getType().equals(VideoStreamSessionManager.SessionType.broadcast)) { 265 + if (transaction.getType().equals(InviteSessionType.BROADCAST)) {
259 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(transaction.getDeviceId()); 266 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(transaction.getDeviceId());
260 if (parentPlatform != null) { 267 if (parentPlatform != null) {
261 try { 268 try {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2
3 -import com.alibaba.fastjson2.JSONObject;  
4 import com.genersoft.iot.vmp.common.VideoManagerConstants; 3 import com.genersoft.iot.vmp.common.VideoManagerConstants;
  4 +import com.genersoft.iot.vmp.common.StreamInfo;
5 import com.genersoft.iot.vmp.conf.DynamicTask; 5 import com.genersoft.iot.vmp.conf.DynamicTask;
6 import com.genersoft.iot.vmp.conf.SipConfig; 6 import com.genersoft.iot.vmp.conf.SipConfig;
7 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
8 import com.genersoft.iot.vmp.gb28181.bean.*; 8 import com.genersoft.iot.vmp.gb28181.bean.*;
9 -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;  
10 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; 9 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
11 -import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;  
12 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 10 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  11 +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
13 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 12 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
14 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; 13 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
15 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 14 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
@@ -23,7 +22,12 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; @@ -23,7 +22,12 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
23 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 22 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
24 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 23 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
25 import com.genersoft.iot.vmp.media.zlm.dto.*; 24 import com.genersoft.iot.vmp.media.zlm.dto.*;
26 -import com.genersoft.iot.vmp.service.*; 25 +import com.genersoft.iot.vmp.service.IMediaServerService;
  26 +import com.genersoft.iot.vmp.service.IPlayService;
  27 +import com.genersoft.iot.vmp.service.IStreamProxyService;
  28 +import com.genersoft.iot.vmp.service.IStreamPushService;
  29 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  30 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
27 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 31 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
28 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 32 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
29 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; 33 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
@@ -79,6 +83,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -79,6 +83,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
79 private IRedisCatchStorage redisCatchStorage; 83 private IRedisCatchStorage redisCatchStorage;
80 84
81 @Autowired 85 @Autowired
  86 + private SSRCFactory ssrcFactory;
  87 +
  88 + @Autowired
82 private DynamicTask dynamicTask; 89 private DynamicTask dynamicTask;
83 90
84 @Autowired 91 @Autowired
@@ -90,8 +97,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -90,8 +97,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
90 @Autowired 97 @Autowired
91 private SIPSender sipSender; 98 private SIPSender sipSender;
92 99
93 - @Autowired  
94 - private AudioBroadcastManager audioBroadcastManager; 100 + @Autowired
  101 + private AudioBroadcastManager audioBroadcastManager;
95 102
96 @Autowired 103 @Autowired
97 private ZLMRTPServerFactory zlmrtpServerFactory; 104 private ZLMRTPServerFactory zlmrtpServerFactory;
@@ -102,8 +109,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -102,8 +109,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
102 @Autowired 109 @Autowired
103 private ISIPCommander commander; 110 private ISIPCommander commander;
104 111
105 - @Autowired  
106 - private ZLMRESTfulUtils zlmresTfulUtils; 112 + @Autowired
  113 + private ZLMRESTfulUtils zlmresTfulUtils;
107 114
108 @Autowired 115 @Autowired
109 private ZlmHttpHookSubscribe zlmHttpHookSubscribe; 116 private ZlmHttpHookSubscribe zlmHttpHookSubscribe;
@@ -112,28 +119,24 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -112,28 +119,24 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
112 private SIPProcessorObserver sipProcessorObserver; 119 private SIPProcessorObserver sipProcessorObserver;
113 120
114 @Autowired 121 @Autowired
115 - private VideoStreamSessionManager sessionManager;  
116 -  
117 - @Autowired  
118 private UserSetting userSetting; 122 private UserSetting userSetting;
119 123
120 @Autowired 124 @Autowired
121 private ZLMMediaListManager mediaListManager; 125 private ZLMMediaListManager mediaListManager;
122 126
123 - @Autowired  
124 - private DeferredResultHolder resultHolder; 127 + @Autowired
  128 + private DeferredResultHolder resultHolder;
125 129
126 - @Autowired  
127 - private ZlmHttpHookSubscribe subscribe; 130 + @Autowired
  131 + private ZlmHttpHookSubscribe subscribe;
128 132
129 - @Autowired  
130 - private SipConfig config; 133 + @Autowired
  134 + private SipConfig config;
131 135
132 @Autowired 136 @Autowired
133 private VideoStreamSessionManager streamSession; 137 private VideoStreamSessionManager streamSession;
134 138
135 139
136 -  
137 @Autowired 140 @Autowired
138 private RedisGbPlayMsgListener redisGbPlayMsgListener; 141 private RedisGbPlayMsgListener redisGbPlayMsgListener;
139 142
@@ -153,7 +156,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -153,7 +156,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
153 public void process(RequestEvent evt) { 156 public void process(RequestEvent evt) {
154 // Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令 157 // Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
155 try { 158 try {
156 - SIPRequest request = (SIPRequest)evt.getRequest(); 159 + SIPRequest request = (SIPRequest) evt.getRequest();
157 String channelId = SipUtils.getChannelIdFromRequest(request); 160 String channelId = SipUtils.getChannelIdFromRequest(request);
158 String requesterId = SipUtils.getUserIdFromFromHeader(request); 161 String requesterId = SipUtils.getUserIdFromFromHeader(request);
159 CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); 162 CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
@@ -167,27 +170,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -167,27 +170,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
167 } 170 }
168 return; 171 return;
169 } 172 }
170 - String ssrc = null;  
171 - SessionDescription sdp = null;  
172 - String ssrcDefault = "0000000000";  
173 - if (channelId == null) {  
174 - // 解析sdp消息, 使用jainsip 自带的sdp解析方式  
175 - String contentString = new String(request.getRawContent());  
176 -  
177 - // jainSip不支持y=字段, 移除以解析。  
178 - int ssrcIndex = contentString.indexOf("y=");  
179 -  
180 - if (ssrcIndex >= 0) {  
181 - //ssrc规定长度为10个字节,不取余下长度以避免后续还有“f=”字段  
182 - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
183 - String substring = contentString.substring(0, contentString.indexOf("y="));  
184 - sdp = SdpFactory.getInstance().createSessionDescription(substring);  
185 - } else {  
186 - ssrc = ssrcDefault;  
187 - sdp = SdpFactory.getInstance().createSessionDescription(contentString);  
188 - }  
189 - channelId = sdp.getOrigin().getUsername();  
190 - }  
191 173
192 174
193 // 查询请求是否来自上级平台\设备 175 // 查询请求是否来自上级平台\设备
@@ -249,7 +231,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -249,7 +231,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
249 } 231 }
250 return; 232 return;
251 } 233 }
252 - }else if("proxy".equals(gbStream.getStreamType())){ 234 + } else if ("proxy".equals(gbStream.getStreamType())) {
253 proxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(gbStream.getApp(), gbStream.getStream()); 235 proxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(gbStream.getApp(), gbStream.getStream());
254 if (proxyByAppAndStream == null) { 236 if (proxyByAppAndStream == null) {
255 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId); 237 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId);
@@ -285,23 +267,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -285,23 +267,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
285 } 267 }
286 return; 268 return;
287 } 269 }
288 - if (sdp == null || ssrc == null) {  
289 - // 解析sdp消息, 使用jainsip 自带的sdp解析方式  
290 - String contentString = new String(request.getRawContent());  
291 -  
292 - // jainSip不支持y=字段, 移除以解析。  
293 - int ssrcIndex = contentString.indexOf("y=");  
294 - if (ssrcIndex >= 0) {  
295 - //ssrc规定长度为10个字节,不取余下长度以避免后续还有“f=”字段  
296 - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
297 - String substring = contentString.substring(0, contentString.indexOf("y="));  
298 - sdp = SdpFactory.getInstance().createSessionDescription(substring);  
299 - } else {  
300 - ssrc = ssrcDefault;  
301 - sdp = SdpFactory.getInstance().createSessionDescription(contentString);  
302 - }  
303 - } 270 + // 解析sdp消息, 使用jainsip 自带的sdp解析方式
  271 + String contentString = new String(request.getRawContent());
304 272
  273 + // jainSip不支持y=字段, 移除以解析。
  274 + // 检查是否有y字段
  275 + int ssrcIndex = contentString.indexOf("y=");
  276 +
  277 + SessionDescription sdp;
  278 + if (ssrcIndex >= 0) {
  279 + //ssrc规定长度为10个字节,不取余下长度以避免后续还有“f=”字段
  280 + String substring = contentString.substring(0, ssrcIndex);
  281 + sdp = SdpFactory.getInstance().createSessionDescription(substring);
  282 + } else {
  283 + sdp = SdpFactory.getInstance().createSessionDescription(contentString);
  284 + }
305 String sessionName = sdp.getSessionName().getValue(); 285 String sessionName = sdp.getSessionName().getValue();
306 286
307 Long startTime = null; 287 Long startTime = null;
@@ -363,7 +343,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -363,7 +343,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
363 String username = sdp.getOrigin().getUsername(); 343 String username = sdp.getOrigin().getUsername();
364 String addressStr = sdp.getConnection().getAddress(); 344 String addressStr = sdp.getConnection().getAddress();
365 345
366 - logger.info("[上级点播]用户:{}, 通道:{}, 地址:{}:{}, ssrc:{}", username, channelId, addressStr, port, ssrc); 346 +
367 Device device = null; 347 Device device = null;
368 // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标 348 // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标
369 if (channel != null) { 349 if (channel != null) {
@@ -387,6 +367,25 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -387,6 +367,25 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
387 } 367 }
388 return; 368 return;
389 } 369 }
  370 +
  371 + String ssrc;
  372 + if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) {
  373 + // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式
  374 + ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
  375 + } else {
  376 + ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  377 + }
  378 + String streamTypeStr = null;
  379 + if (mediaTransmissionTCP) {
  380 + if (tcpActive) {
  381 + streamTypeStr = "TCP-ACTIVE";
  382 + } else {
  383 + streamTypeStr = "TCP-PASSIVE";
  384 + }
  385 + } else {
  386 + streamTypeStr = "UDP";
  387 + }
  388 + logger.info("[上级Invite] {}, 平台:{}, 通道:{}, 收流地址:{}:{},收流方式:{}, ssrc:{}", sessionName, username, channelId, addressStr, port, streamTypeStr, ssrc);
390 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, 389 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
391 device.getDeviceId(), channelId, mediaTransmissionTCP, platform.isRtcp()); 390 device.getDeviceId(), channelId, mediaTransmissionTCP, platform.isRtcp());
392 391
@@ -407,11 +406,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -407,11 +406,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
407 406
408 Long finalStartTime = startTime; 407 Long finalStartTime = startTime;
409 Long finalStopTime = stopTime; 408 Long finalStopTime = stopTime;
410 - String finalChannelId = channelId;  
411 - ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON) -> {  
412 - String app = responseJSON.getString("app");  
413 - String stream = responseJSON.getString("stream");  
414 - logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", app, stream); 409 + InviteErrorCallback<Object> hookEvent = (code, msg, data) -> {
  410 + StreamInfo streamInfo = (StreamInfo) data;
  411 + MediaServerItem mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
  412 + logger.info("[上级Invite]下级已经开始推流。 回复200OK(SDP), {}/{}", streamInfo.getApp(), streamInfo.getStream());
415 // * 0 等待设备推流上来 413 // * 0 等待设备推流上来
416 // * 1 下级已经推流,等待上级平台回复ack 414 // * 1 下级已经推流,等待上级平台回复ack
417 // * 2 推流中 415 // * 2 推流中
@@ -420,7 +418,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -420,7 +418,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
420 418
421 StringBuffer content = new StringBuffer(200); 419 StringBuffer content = new StringBuffer(200);
422 content.append("v=0\r\n"); 420 content.append("v=0\r\n");
423 - content.append("o=" + finalChannelId + " 0 0 IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n"); 421 + content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n");
424 content.append("s=" + sessionName + "\r\n"); 422 content.append("s=" + sessionName + "\r\n");
425 content.append("c=IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n"); 423 content.append("c=IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n");
426 if ("Playback".equalsIgnoreCase(sessionName)) { 424 if ("Playback".equalsIgnoreCase(sessionName)) {
@@ -462,111 +460,118 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -462,111 +460,118 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
462 logger.error("[命令发送失败] 国标级联 回复SdpAck", e); 460 logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
463 } 461 }
464 }; 462 };
465 - SipSubscribe.Event errorEvent = ((event) -> { 463 + InviteErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
466 // 未知错误。直接转发设备点播的错误 464 // 未知错误。直接转发设备点播的错误
467 try { 465 try {
468 - Response response = getMessageFactory().createResponse(event.statusCode, evt.getRequest());  
469 - sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);  
470 - } catch (ParseException | SipException e) { 466 + if (statusCode > 0) {
  467 + Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
  468 + sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
  469 + }
  470 + } catch (ParseException | SipException e) {
471 logger.error("未处理的异常 ", e); 471 logger.error("未处理的异常 ", e);
472 } 472 }
473 }); 473 });
474 sendRtpItem.setApp("rtp"); 474 sendRtpItem.setApp("rtp");
475 if ("Playback".equalsIgnoreCase(sessionName)) { 475 if ("Playback".equalsIgnoreCase(sessionName)) {
476 sendRtpItem.setPlayType(InviteStreamType.PLAYBACK); 476 sendRtpItem.setPlayType(InviteStreamType.PLAYBACK);
477 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, device.isSsrcCheck(), true); 477 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, false, device.getStreamModeForParam());
478 sendRtpItem.setStream(ssrcInfo.getStream()); 478 sendRtpItem.setStream(ssrcInfo.getStream());
479 // 写入redis, 超时时回复 479 // 写入redis, 超时时回复
480 redisCatchStorage.updateSendRTPSever(sendRtpItem); 480 redisCatchStorage.updateSendRTPSever(sendRtpItem);
481 playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), 481 playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
482 - DateUtil.formatter.format(end), null, result -> {  
483 - if (result.getCode() != 0) {  
484 - logger.warn("录像回放失败");  
485 - if (result.getEvent() != null) {  
486 - errorEvent.response(result.getEvent());  
487 - }  
488 - redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), finalChannelId, callIdHeader.getCallId(), null);  
489 - try {  
490 - responseAck(request, Response.REQUEST_TIMEOUT);  
491 - } catch (SipException | InvalidArgumentException | ParseException e) {  
492 - logger.error("[命令发送失败] 国标级联 录像回放 发送REQUEST_TIMEOUT: {}", e.getMessage());  
493 - } 482 + DateUtil.formatter.format(end),
  483 + (code, msg, data) -> {
  484 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  485 + hookEvent.run(code, msg, data);
  486 + } else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()) {
  487 + logger.info("[录像回放]超时, 用户:{}, 通道:{}", username, channelId);
  488 + redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
  489 + errorEvent.run(code, msg, data);
  490 + } else {
  491 + errorEvent.run(code, msg, data);
  492 + }
  493 + });
  494 + } else if ("Download".equalsIgnoreCase(sessionName)) {
  495 + // 获取指定的下载速度
  496 + Vector sdpMediaDescriptions = sdp.getMediaDescriptions(true);
  497 + MediaDescription mediaDescription = null;
  498 + String downloadSpeed = "1";
  499 + if (sdpMediaDescriptions.size() > 0) {
  500 + mediaDescription = (MediaDescription) sdpMediaDescriptions.get(0);
  501 + }
  502 + if (mediaDescription != null) {
  503 + downloadSpeed = mediaDescription.getAttribute("downloadspeed");
  504 + }
  505 +
  506 + sendRtpItem.setPlayType(InviteStreamType.DOWNLOAD);
  507 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, false, device.getStreamModeForParam());
  508 + sendRtpItem.setStream(ssrcInfo.getStream());
  509 + // 写入redis, 超时时回复
  510 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  511 + playService.download(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
  512 + DateUtil.formatter.format(end), Integer.parseInt(downloadSpeed),
  513 + (code, msg, data) -> {
  514 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  515 + hookEvent.run(code, msg, data);
  516 + } else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()) {
  517 + logger.info("[录像下载]超时, 用户:{}, 通道:{}", username, channelId);
  518 + redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
  519 + errorEvent.run(code, msg, data);
494 } else { 520 } else {
495 - if (result.getMediaServerItem() != null) {  
496 - hookEvent.response(result.getMediaServerItem(), result.getResponse());  
497 - } 521 + errorEvent.run(code, msg, data);
498 } 522 }
499 }); 523 });
500 } else { 524 } else {
501 sendRtpItem.setPlayType(InviteStreamType.PLAY); 525 sendRtpItem.setPlayType(InviteStreamType.PLAY);
502 - SsrcTransaction playTransaction = sessionManager.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);  
503 - if (playTransaction != null) {  
504 - Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, "rtp", playTransaction.getStream());  
505 - if (!streamReady) {  
506 - boolean hasRtpServer = mediaServerService.checkRtpServer(mediaServerItem, "rtp", playTransaction.getStream());  
507 - if (hasRtpServer) {  
508 - logger.info("[上级点播]已经开启rtpServer但是尚未收到流,开启监听流的到来");  
509 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", playTransaction.getStream(), true, "rtsp", mediaServerItem.getId());  
510 - zlmHttpHookSubscribe.addSubscribe(hookSubscribe, hookEvent);  
511 - }else {  
512 - playTransaction = null;  
513 - }  
514 - }  
515 - }  
516 - if (playTransaction == null) {  
517 - String streamId = null;  
518 - if (mediaServerItem.isRtpEnable()) {  
519 - streamId = String.format("%s_%s", device.getDeviceId(), channelId);  
520 - }  
521 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false);  
522 - logger.info(JSONObject.toJSONString(ssrcInfo));  
523 - sendRtpItem.setStream(ssrcInfo.getStream());  
524 - sendRtpItem.setSsrc(ssrc.equals(ssrcDefault) ? ssrcInfo.getSsrc() : ssrc);  
525 -  
526 - // 写入redis, 超时时回复  
527 - redisCatchStorage.updateSendRTPSever(sendRtpItem);  
528 - playService.play(mediaServerItem, ssrcInfo, device, channelId, hookEvent, errorEvent, (code, msg) -> {  
529 - logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, finalChannelId);  
530 - redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), finalChannelId, callIdHeader.getCallId(), null);  
531 - }); 526 + String streamId = null;
  527 + if (mediaServerItem.isRtpEnable()) {
  528 + streamId = String.format("%s_%s", device.getDeviceId(), channelId);
532 } else { 529 } else {
533 - sendRtpItem.setStream(playTransaction.getStream());  
534 - // 写入redis, 超时时回复  
535 - redisCatchStorage.updateSendRTPSever(sendRtpItem);  
536 - JSONObject jsonObject = new JSONObject();  
537 - jsonObject.put("app", sendRtpItem.getApp());  
538 - jsonObject.put("stream", sendRtpItem.getStream());  
539 - hookEvent.response(mediaServerItem, jsonObject); 530 + streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
540 } 531 }
  532 + sendRtpItem.setStream(streamId);
  533 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  534 + playService.play(mediaServerItem, device.getDeviceId(), channelId, ((code, msg, data) -> {
  535 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  536 + hookEvent.run(code, msg, data);
  537 + } else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()) {
  538 + logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId);
  539 + redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
  540 + errorEvent.run(code, msg, data);
  541 + } else {
  542 + errorEvent.run(code, msg, data);
  543 + }
  544 + }));
  545 +
541 } 546 }
542 } else if (gbStream != null) { 547 } else if (gbStream != null) {
543 - if(ssrc.equals(ssrcDefault))  
544 - {  
545 - SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();  
546 - if(ssrcConfig != null)  
547 - {  
548 - ssrc = ssrcConfig.getPlaySsrc();  
549 - ssrcConfig.releaseSsrc(ssrc);  
550 - } 548 +
  549 + String ssrc;
  550 + if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) {
  551 + // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式
  552 + ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
  553 + } else {
  554 + ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
551 } 555 }
552 - if("push".equals(gbStream.getStreamType())) { 556 +
  557 + if ("push".equals(gbStream.getStreamType())) {
553 if (streamPushItem != null && streamPushItem.isPushIng()) { 558 if (streamPushItem != null && streamPushItem.isPushIng()) {
554 // 推流状态 559 // 推流状态
555 pushStream(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, 560 pushStream(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
556 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); 561 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
557 } else { 562 } else {
558 // 未推流 拉起 563 // 未推流 拉起
559 - notifyStreamOnline(evt, request,gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, 564 + notifyStreamOnline(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
560 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); 565 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
561 } 566 }
562 - }else if ("proxy".equals(gbStream.getStreamType())){ 567 + } else if ("proxy".equals(gbStream.getStreamType())) {
563 if (null != proxyByAppAndStream) { 568 if (null != proxyByAppAndStream) {
564 - if(proxyByAppAndStream.isStatus()){  
565 - pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive, 569 + if (proxyByAppAndStream.isStatus()) {
  570 + pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive,
566 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); 571 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
567 - }else{ 572 + } else {
568 //开启代理拉流 573 //开启代理拉流
569 - notifyStreamOnline(evt, request,gbStream, null, platform, callIdHeader, mediaServerItem, port, tcpActive, 574 + notifyStreamOnline(evt, request, gbStream, null, platform, callIdHeader, mediaServerItem, port, tcpActive,
570 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); 575 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
571 } 576 }
572 } 577 }
@@ -586,42 +591,43 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -586,42 +591,43 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
586 * 安排推流 591 * 安排推流
587 */ 592 */
588 private void pushProxyStream(RequestEvent evt, SIPRequest request, GbStream gbStream, ParentPlatform platform, 593 private void pushProxyStream(RequestEvent evt, SIPRequest request, GbStream gbStream, ParentPlatform platform,
589 - CallIdHeader callIdHeader, MediaServerItem mediaServerItem,  
590 - int port, Boolean tcpActive, boolean mediaTransmissionTCP,  
591 - String channelId, String addressStr, String ssrc, String requesterId) {  
592 - Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());  
593 - if (streamReady) {  
594 - // 自平台内容  
595 - SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,  
596 - gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());  
597 -  
598 - if (sendRtpItem == null) {  
599 - logger.warn("服务器端口资源不足");  
600 - try {  
601 - responseAck(request, Response.BUSY_HERE);  
602 - } catch (SipException | InvalidArgumentException | ParseException e) {  
603 - logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());  
604 - }  
605 - return;  
606 - }  
607 - if (tcpActive != null) {  
608 - sendRtpItem.setTcpActive(tcpActive);  
609 - }  
610 - sendRtpItem.setPlayType(InviteStreamType.PUSH);  
611 - // 写入redis, 超时时回复  
612 - sendRtpItem.setStatus(1);  
613 - sendRtpItem.setCallId(callIdHeader.getCallId());  
614 - sendRtpItem.setFromTag(request.getFromTag());  
615 -  
616 - SIPResponse response = sendStreamAck(mediaServerItem, request, sendRtpItem, platform, evt);  
617 - if (response != null) {  
618 - sendRtpItem.setToTag(response.getToTag()); 594 + CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
  595 + int port, Boolean tcpActive, boolean mediaTransmissionTCP,
  596 + String channelId, String addressStr, String ssrc, String requesterId) {
  597 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
  598 + if (streamReady != null && streamReady) {
  599 + // 自平台内容
  600 + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
  601 + gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());
  602 +
  603 + if (sendRtpItem == null) {
  604 + logger.warn("服务器端口资源不足");
  605 + try {
  606 + responseAck(request, Response.BUSY_HERE);
  607 + } catch (SipException | InvalidArgumentException | ParseException e) {
  608 + logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
619 } 609 }
620 - redisCatchStorage.updateSendRTPSever(sendRtpItem); 610 + return;
  611 + }
  612 + if (tcpActive != null) {
  613 + sendRtpItem.setTcpActive(tcpActive);
  614 + }
  615 + sendRtpItem.setPlayType(InviteStreamType.PUSH);
  616 + // 写入redis, 超时时回复
  617 + sendRtpItem.setStatus(1);
  618 + sendRtpItem.setCallId(callIdHeader.getCallId());
  619 + sendRtpItem.setFromTag(request.getFromTag());
  620 +
  621 + SIPResponse response = sendStreamAck(mediaServerItem, request, sendRtpItem, platform, evt);
  622 + if (response != null) {
  623 + sendRtpItem.setToTag(response.getToTag());
  624 + }
  625 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
621 626
622 } 627 }
623 628
624 } 629 }
  630 +
625 private void pushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform, 631 private void pushStream(RequestEvent evt, SIPRequest request, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
626 CallIdHeader callIdHeader, MediaServerItem mediaServerItem, 632 CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
627 int port, Boolean tcpActive, boolean mediaTransmissionTCP, 633 int port, Boolean tcpActive, boolean mediaTransmissionTCP,
@@ -629,7 +635,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -629,7 +635,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
629 // 推流 635 // 推流
630 if (streamPushItem.isSelf()) { 636 if (streamPushItem.isSelf()) {
631 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); 637 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
632 - if (streamReady) { 638 + if (streamReady != null && streamReady) {
633 // 自平台内容 639 // 自平台内容
634 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, 640 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
635 gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp()); 641 gbStream.getApp(), gbStream.getStream(), channelId, mediaTransmissionTCP, platform.isRtcp());
@@ -661,7 +667,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -661,7 +667,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
661 667
662 } else { 668 } else {
663 // 不在线 拉起 669 // 不在线 拉起
664 - notifyStreamOnline(evt, request,gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, 670 + notifyStreamOnline(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
665 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); 671 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
666 } 672 }
667 673
@@ -671,6 +677,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -671,6 +677,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
671 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); 677 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
672 } 678 }
673 } 679 }
  680 +
674 /** 681 /**
675 * 通知流上线 682 * 通知流上线
676 */ 683 */
@@ -688,7 +695,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -688,7 +695,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
688 String stream = responseJSON.getString("stream"); 695 String stream = responseJSON.getString("stream");
689 logger.info("[上级点播]拉流代理已经就绪, {}/{}", app, stream); 696 logger.info("[上级点播]拉流代理已经就绪, {}/{}", app, stream);
690 dynamicTask.stop(callIdHeader.getCallId()); 697 dynamicTask.stop(callIdHeader.getCallId());
691 - pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive, 698 + pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive,
692 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); 699 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
693 }); 700 });
694 dynamicTask.startDelay(callIdHeader.getCallId(), () -> { 701 dynamicTask.startDelay(callIdHeader.getCallId(), () -> {
@@ -707,7 +714,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -707,7 +714,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
707 } 714 }
708 715
709 716
710 -  
711 } else if ("push".equals(gbStream.getStreamType())) { 717 } else if ("push".equals(gbStream.getStreamType())) {
712 if (!platform.isStartOfflinePush()) { 718 if (!platform.isStartOfflinePush()) {
713 // 平台设置中关闭了拉起离线的推流则直接回复 719 // 平台设置中关闭了拉起离线的推流则直接回复
@@ -811,7 +817,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -811,7 +817,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
811 // 发送redis消息 817 // 发送redis消息
812 redisGbPlayMsgListener.sendMsg(streamPushItem.getServerId(), streamPushItem.getMediaServerId(), 818 redisGbPlayMsgListener.sendMsg(streamPushItem.getServerId(), streamPushItem.getMediaServerId(),
813 streamPushItem.getApp(), streamPushItem.getStream(), addressStr, port, ssrc, requesterId, 819 streamPushItem.getApp(), streamPushItem.getStream(), addressStr, port, ssrc, requesterId,
814 - channelId, mediaTransmissionTCP, platform.isRtcp(),null, responseSendItemMsg -> { 820 + channelId, mediaTransmissionTCP, platform.isRtcp(), null, responseSendItemMsg -> {
815 SendRtpItem sendRtpItem = responseSendItemMsg.getSendRtpItem(); 821 SendRtpItem sendRtpItem = responseSendItemMsg.getSendRtpItem();
816 if (sendRtpItem == null || responseSendItemMsg.getMediaServerItem() == null) { 822 if (sendRtpItem == null || responseSendItemMsg.getMediaServerItem() == null) {
817 logger.warn("服务器端口资源不足"); 823 logger.warn("服务器端口资源不足");
@@ -836,7 +842,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -836,7 +842,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
836 sendRtpItem.setCallId(callIdHeader.getCallId()); 842 sendRtpItem.setCallId(callIdHeader.getCallId());
837 843
838 sendRtpItem.setFromTag(request.getFromTag()); 844 sendRtpItem.setFromTag(request.getFromTag());
839 - SIPResponse response = sendStreamAck(responseSendItemMsg.getMediaServerItem(), request,sendRtpItem, platform, evt); 845 + SIPResponse response = sendStreamAck(responseSendItemMsg.getMediaServerItem(), request, sendRtpItem, platform, evt);
840 if (response != null) { 846 if (response != null) {
841 sendRtpItem.setToTag(response.getToTag()); 847 sendRtpItem.setToTag(response.getToTag());
842 } 848 }
@@ -877,8 +883,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -877,8 +883,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
877 content.append("t=0 0\r\n"); 883 content.append("t=0 0\r\n");
878 // 非严格模式端口不统一, 增加兼容性,修改为一个不为0的端口 884 // 非严格模式端口不统一, 增加兼容性,修改为一个不为0的端口
879 int localPort = sendRtpItem.getLocalPort(); 885 int localPort = sendRtpItem.getLocalPort();
880 - if(localPort == 0)  
881 - { 886 + if (localPort == 0) {
882 localPort = new Random().nextInt(65535) + 1; 887 localPort = new Random().nextInt(65535) + 1;
883 } 888 }
884 content.append("m=video " + localPort + " RTP/AVP 96\r\n"); 889 content.append("m=video " + localPort + " RTP/AVP 96\r\n");
@@ -953,7 +958,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -953,7 +958,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
953 } 958 }
954 if (device != null) { 959 if (device != null) {
955 logger.info("收到设备" + requesterId + "的语音广播Invite请求"); 960 logger.info("收到设备" + requesterId + "的语音广播Invite请求");
956 - String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + device.getDeviceId() + broadcastCatch.getChannelId(); 961 + String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + device.getDeviceId() + broadcastCatch.getChannelId();
957 dynamicTask.stop(key); 962 dynamicTask.stop(key);
958 try { 963 try {
959 responseAck(request, Response.TRYING); 964 responseAck(request, Response.TRYING);
@@ -986,7 +991,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -986,7 +991,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
986 boolean mediaTransmissionTCP = false; 991 boolean mediaTransmissionTCP = false;
987 Boolean tcpActive = null; 992 Boolean tcpActive = null;
988 for (int i = 0; i < mediaDescriptions.size(); i++) { 993 for (int i = 0; i < mediaDescriptions.size(); i++) {
989 - MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i); 994 + MediaDescription mediaDescription = (MediaDescription) mediaDescriptions.get(i);
990 Media media = mediaDescription.getMedia(); 995 Media media = mediaDescription.getMedia();
991 996
992 Vector mediaFormats = media.getMediaFormats(false); 997 Vector mediaFormats = media.getMediaFormats(false);
@@ -1022,7 +1027,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1022,7 +1027,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1022 } 1027 }
1023 String addressStr = sdp.getOrigin().getAddress(); 1028 String addressStr = sdp.getOrigin().getAddress();
1024 logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc, 1029 logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc,
1025 - mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP"); 1030 + mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP");
1026 1031
1027 MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem(); 1032 MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem();
1028 if (mediaServerItem == null) { 1033 if (mediaServerItem == null) {
@@ -1036,7 +1041,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1036,7 +1041,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1036 return; 1041 return;
1037 } 1042 }
1038 logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, ssrc, 1043 logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, ssrc,
1039 - mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP", sdp.getSessionName().getValue()); 1044 + mediaTransmissionTCP ? (tcpActive ? "TCP主动" : "TCP被动") : "UDP", sdp.getSessionName().getValue());
1040 1045
1041 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, 1046 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
1042 device.getDeviceId(), broadcastCatch.getChannelId(), 1047 device.getDeviceId(), broadcastCatch.getChannelId(),
@@ -1076,7 +1081,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1076,7 +1081,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1076 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream()); 1081 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream());
1077 if (streamReady) { 1082 if (streamReady) {
1078 sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, ssrc); 1083 sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, ssrc);
1079 - }else { 1084 + } else {
1080 logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", broadcastCatch.getApp(), broadcastCatch.getStream()); 1085 logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", broadcastCatch.getApp(), broadcastCatch.getStream());
1081 try { 1086 try {
1082 responseAck(request, Response.GONE); 1087 responseAck(request, Response.GONE);
@@ -1093,29 +1098,30 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1093,29 +1098,30 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1093 } else { 1098 } else {
1094 logger.warn("来自无效设备/平台的请求"); 1099 logger.warn("来自无效设备/平台的请求");
1095 try { 1100 try {
1096 - responseAck(request, Response.BAD_REQUEST);; // 不支持的格式,发415 1101 + responseAck(request, Response.BAD_REQUEST);
  1102 + ; // 不支持的格式,发415
1097 } catch (SipException | InvalidArgumentException | ParseException e) { 1103 } catch (SipException | InvalidArgumentException | ParseException e) {
1098 logger.error("[命令发送失败] invite 来自无效设备/平台的请求, {}", e.getMessage()); 1104 logger.error("[命令发送失败] invite 来自无效设备/平台的请求, {}", e.getMessage());
1099 } 1105 }
1100 } 1106 }
1101 } 1107 }
1102 1108
1103 - SIPResponse sendOk(Device device, SendRtpItem sendRtpItem, SessionDescription sdp, SIPRequest request, MediaServerItem mediaServerItem, boolean mediaTransmissionTCP, String ssrc){ 1109 + SIPResponse sendOk(Device device, SendRtpItem sendRtpItem, SessionDescription sdp, SIPRequest request, MediaServerItem mediaServerItem, boolean mediaTransmissionTCP, String ssrc) {
1104 SIPResponse sipResponse = null; 1110 SIPResponse sipResponse = null;
1105 try { 1111 try {
1106 sendRtpItem.setStatus(2); 1112 sendRtpItem.setStatus(2);
1107 redisCatchStorage.updateSendRTPSever(sendRtpItem); 1113 redisCatchStorage.updateSendRTPSever(sendRtpItem);
1108 StringBuffer content = new StringBuffer(200); 1114 StringBuffer content = new StringBuffer(200);
1109 content.append("v=0\r\n"); 1115 content.append("v=0\r\n");
1110 - content.append("o="+ config.getId() +" "+ sdp.getOrigin().getSessionId() +" " + sdp.getOrigin().getSessionVersion() + " IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); 1116 + content.append("o=" + config.getId() + " " + sdp.getOrigin().getSessionId() + " " + sdp.getOrigin().getSessionVersion() + " IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
1111 content.append("s=Play\r\n"); 1117 content.append("s=Play\r\n");
1112 - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); 1118 + content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
1113 content.append("t=0 0\r\n"); 1119 content.append("t=0 0\r\n");
1114 1120
1115 if (mediaTransmissionTCP) { 1121 if (mediaTransmissionTCP) {
1116 - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");  
1117 - }else {  
1118 - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n"); 1122 + content.append("m=audio " + sendRtpItem.getLocalPort() + " TCP/RTP/AVP 8\r\n");
  1123 + } else {
  1124 + content.append("m=audio " + sendRtpItem.getLocalPort() + " RTP/AVP 8\r\n");
1119 } 1125 }
1120 1126
1121 content.append("a=rtpmap:8 PCMA/8000/1\r\n"); 1127 content.append("a=rtpmap:8 PCMA/8000/1\r\n");
@@ -1125,11 +1131,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -1125,11 +1131,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1125 content.append("a=connection:new\r\n"); 1131 content.append("a=connection:new\r\n");
1126 if (!sendRtpItem.isTcpActive()) { 1132 if (!sendRtpItem.isTcpActive()) {
1127 content.append("a=setup:active\r\n"); 1133 content.append("a=setup:active\r\n");
1128 - }else { 1134 + } else {
1129 content.append("a=setup:passive\r\n"); 1135 content.append("a=setup:passive\r\n");
1130 } 1136 }
1131 } 1137 }
1132 - content.append("y="+ ssrc + "\r\n"); 1138 + content.append("y=" + ssrc + "\r\n");
1133 content.append("f=v/////a/1/8/1\r\n"); 1139 content.append("f=v/////a/1/8/1\r\n");
1134 1140
1135 ParentPlatform parentPlatform = new ParentPlatform(); 1141 ParentPlatform parentPlatform = new ParentPlatform();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
  2 +
  3 +import com.genersoft.iot.vmp.conf.DynamicTask;
  4 +import com.genersoft.iot.vmp.conf.UserSetting;
  5 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  6 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  7 +import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
  8 +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
  10 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  11 +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
  12 +import com.genersoft.iot.vmp.service.IDeviceChannelService;
  13 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  14 +import org.dom4j.DocumentException;
  15 +import org.dom4j.Element;
  16 +import org.slf4j.Logger;
  17 +import org.slf4j.LoggerFactory;
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.stereotype.Component;
  20 +
  21 +import javax.sip.RequestEvent;
  22 +import javax.sip.header.FromHeader;
  23 +import java.util.*;
  24 +import java.util.concurrent.ConcurrentHashMap;
  25 +import java.util.concurrent.CopyOnWriteArrayList;
  26 +
  27 +/**
  28 + * SIP命令类型: NOTIFY请求中的目录请求处理
  29 + */
  30 +@Component
  31 +public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent {
  32 +
  33 +
  34 + private final static Logger logger = LoggerFactory.getLogger(NotifyRequestForCatalogProcessor.class);
  35 +
  36 + private final List<DeviceChannel> updateChannelOnlineList = new CopyOnWriteArrayList<>();
  37 + private final List<DeviceChannel> updateChannelOfflineList = new CopyOnWriteArrayList<>();
  38 + private final Map<String, DeviceChannel> updateChannelMap = new ConcurrentHashMap<>();
  39 +
  40 + private final Map<String, DeviceChannel> addChannelMap = new ConcurrentHashMap<>();
  41 + private final List<DeviceChannel> deleteChannelList = new CopyOnWriteArrayList<>();
  42 +
  43 +
  44 + @Autowired
  45 + private UserSetting userSetting;
  46 +
  47 + @Autowired
  48 + private EventPublisher eventPublisher;
  49 +
  50 + @Autowired
  51 + private IRedisCatchStorage redisCatchStorage;
  52 +
  53 + @Autowired
  54 + private IDeviceChannelService deviceChannelService;
  55 +
  56 + @Autowired
  57 + private DynamicTask dynamicTask;
  58 +
  59 + private final static String talkKey = "notify-request-for-catalog-task";
  60 +
  61 + public void process(RequestEvent evt) {
  62 + try {
  63 + long start = System.currentTimeMillis();
  64 + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
  65 + String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader);
  66 +
  67 + Device device = redisCatchStorage.getDevice(deviceId);
  68 + if (device == null || device.getOnline() == 0) {
  69 + logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId():"" ));
  70 + return;
  71 + }
  72 + Element rootElement = getRootElement(evt, device.getCharset());
  73 + if (rootElement == null) {
  74 + logger.warn("[ 收到目录订阅 ] content cannot be null, {}", evt.getRequest());
  75 + return;
  76 + }
  77 + Element deviceListElement = rootElement.element("DeviceList");
  78 + if (deviceListElement == null) {
  79 + return;
  80 + }
  81 + Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
  82 + if (deviceListIterator != null) {
  83 +
  84 + // 遍历DeviceList
  85 + while (deviceListIterator.hasNext()) {
  86 + Element itemDevice = deviceListIterator.next();
  87 + Element channelDeviceElement = itemDevice.element("DeviceID");
  88 + if (channelDeviceElement == null) {
  89 + continue;
  90 + }
  91 + Element eventElement = itemDevice.element("Event");
  92 + String event;
  93 + if (eventElement == null) {
  94 + logger.warn("[收到目录订阅]:{}, 但是Event为空, 设为默认值 ADD", (device != null ? device.getDeviceId():"" ));
  95 + event = CatalogEvent.ADD;
  96 + }else {
  97 + event = eventElement.getText().toUpperCase();
  98 + }
  99 + DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event);
  100 +
  101 + channel.setDeviceId(device.getDeviceId());
  102 + logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());
  103 + switch (event) {
  104 + case CatalogEvent.ON:
  105 + // 上线
  106 + logger.info("[收到通道上线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  107 + updateChannelOnlineList.add(channel);
  108 + if (updateChannelOnlineList.size() > 300) {
  109 + executeSaveForOnline();
  110 + }
  111 + if (userSetting.getDeviceStatusNotify()) {
  112 + // 发送redis消息
  113 + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), true);
  114 + }
  115 +
  116 + break;
  117 + case CatalogEvent.OFF :
  118 + // 离线
  119 + logger.info("[收到通道离线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  120 + if (userSetting.getRefuseChannelStatusChannelFormNotify()) {
  121 + logger.info("[收到通道离线通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  122 + }else {
  123 + updateChannelOfflineList.add(channel);
  124 + if (updateChannelOfflineList.size() > 300) {
  125 + executeSaveForOffline();
  126 + }
  127 + if (userSetting.getDeviceStatusNotify()) {
  128 + // 发送redis消息
  129 + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), false);
  130 + }
  131 + }
  132 + break;
  133 + case CatalogEvent.VLOST:
  134 + // 视频丢失
  135 + logger.info("[收到通道视频丢失通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  136 + if (userSetting.getRefuseChannelStatusChannelFormNotify()) {
  137 + logger.info("[收到通道视频丢失通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  138 + }else {
  139 + updateChannelOfflineList.add(channel);
  140 + if (updateChannelOfflineList.size() > 300) {
  141 + executeSaveForOffline();
  142 + }
  143 + if (userSetting.getDeviceStatusNotify()) {
  144 + // 发送redis消息
  145 + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), false);
  146 + }
  147 + }
  148 + break;
  149 + case CatalogEvent.DEFECT:
  150 + // 故障
  151 + logger.info("[收到通道视频故障通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  152 + if (userSetting.getRefuseChannelStatusChannelFormNotify()) {
  153 + logger.info("[收到通道视频故障通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  154 + }else {
  155 + updateChannelOfflineList.add(channel);
  156 + if (updateChannelOfflineList.size() > 300) {
  157 + executeSaveForOffline();
  158 + }
  159 + if (userSetting.getDeviceStatusNotify()) {
  160 + // 发送redis消息
  161 + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), false);
  162 + }
  163 + }
  164 + break;
  165 + case CatalogEvent.ADD:
  166 + // 增加
  167 + logger.info("[收到增加通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  168 + // 判断此通道是否存在
  169 + DeviceChannel deviceChannel = deviceChannelService.getOne(deviceId, channel.getChannelId());
  170 + if (deviceChannel != null) {
  171 + channel.setId(deviceChannel.getId());
  172 + updateChannelMap.put(channel.getChannelId(), channel);
  173 + if (updateChannelMap.keySet().size() > 300) {
  174 + executeSaveForUpdate();
  175 + }
  176 + }else {
  177 + addChannelMap.put(channel.getChannelId(), channel);
  178 + if (addChannelMap.keySet().size() > 300) {
  179 + executeSaveForAdd();
  180 + }
  181 + }
  182 +
  183 + break;
  184 + case CatalogEvent.DEL:
  185 + // 删除
  186 + logger.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  187 + deleteChannelList.add(channel);
  188 + if (deleteChannelList.size() > 300) {
  189 + executeSaveForDelete();
  190 + }
  191 + break;
  192 + case CatalogEvent.UPDATE:
  193 + // 更新
  194 + logger.info("[收到更新通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  195 + // 判断此通道是否存在
  196 + DeviceChannel deviceChannelForUpdate = deviceChannelService.getOne(deviceId, channel.getChannelId());
  197 + if (deviceChannelForUpdate != null) {
  198 + channel.setId(deviceChannelForUpdate.getId());
  199 + updateChannelMap.put(channel.getChannelId(), channel);
  200 + if (updateChannelMap.keySet().size() > 300) {
  201 + executeSaveForUpdate();
  202 + }
  203 + }else {
  204 + addChannelMap.put(channel.getChannelId(), channel);
  205 + if (addChannelMap.keySet().size() > 300) {
  206 + executeSaveForAdd();
  207 + }
  208 + }
  209 + break;
  210 + default:
  211 + logger.warn("[ NotifyCatalog ] event not found : {}", event );
  212 +
  213 + }
  214 + // 转发变化信息
  215 + eventPublisher.catalogEventPublish(null, channel, event);
  216 +
  217 + if (updateChannelMap.keySet().size() > 0
  218 + || addChannelMap.keySet().size() > 0
  219 + || updateChannelOnlineList.size() > 0
  220 + || updateChannelOfflineList.size() > 0
  221 + || deleteChannelList.size() > 0) {
  222 +
  223 + if (!dynamicTask.contains(talkKey)) {
  224 + dynamicTask.startDelay(talkKey, this::executeSave, 1000);
  225 + }
  226 + }
  227 + }
  228 + }
  229 + } catch (DocumentException e) {
  230 + logger.error("未处理的异常 ", e);
  231 + }
  232 + }
  233 +
  234 + private void executeSave(){
  235 + System.out.println("定时存储数据");
  236 + executeSaveForUpdate();
  237 + executeSaveForDelete();
  238 + executeSaveForOnline();
  239 + executeSaveForOffline();
  240 + dynamicTask.stop(talkKey);
  241 + }
  242 +
  243 + private void executeSaveForUpdate(){
  244 + if (updateChannelMap.values().size() > 0) {
  245 + ArrayList<DeviceChannel> deviceChannels = new ArrayList<>(updateChannelMap.values());
  246 + updateChannelMap.clear();
  247 + deviceChannelService.batchUpdateChannel(deviceChannels);
  248 + }
  249 +
  250 + }
  251 +
  252 + private void executeSaveForAdd(){
  253 + if (addChannelMap.values().size() > 0) {
  254 + ArrayList<DeviceChannel> deviceChannels = new ArrayList<>(addChannelMap.values());
  255 + addChannelMap.clear();
  256 + deviceChannelService.batchAddChannel(deviceChannels);
  257 + }
  258 + }
  259 +
  260 + private void executeSaveForDelete(){
  261 + if (deleteChannelList.size() > 0) {
  262 + deviceChannelService.deleteChannels(deleteChannelList);
  263 + deleteChannelList.clear();
  264 + }
  265 + }
  266 +
  267 + private void executeSaveForOnline(){
  268 + if (updateChannelOnlineList.size() > 0) {
  269 + deviceChannelService.channelsOnline(updateChannelOnlineList);
  270 + updateChannelOnlineList.clear();
  271 + }
  272 + }
  273 +
  274 + private void executeSaveForOffline(){
  275 + if (updateChannelOfflineList.size() > 0) {
  276 + deviceChannelService.channelsOffline(updateChannelOfflineList);
  277 + updateChannelOfflineList.clear();
  278 + }
  279 + }
  280 +
  281 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -76,12 +76,17 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -76,12 +76,17 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
76 @Autowired 76 @Autowired
77 private IDeviceChannelService deviceChannelService; 77 private IDeviceChannelService deviceChannelService;
78 78
  79 + @Autowired
  80 + private NotifyRequestForCatalogProcessor notifyRequestForCatalogProcessor;
  81 +
79 private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>(); 82 private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>();
80 83
81 @Qualifier("taskExecutor") 84 @Qualifier("taskExecutor")
82 @Autowired 85 @Autowired
83 private ThreadPoolTaskExecutor taskExecutor; 86 private ThreadPoolTaskExecutor taskExecutor;
84 87
  88 + private int maxQueueCount = 30000;
  89 +
85 @Override 90 @Override
86 public void afterPropertiesSet() throws Exception { 91 public void afterPropertiesSet() throws Exception {
87 // 添加消息处理的订阅 92 // 添加消息处理的订阅
@@ -91,43 +96,52 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -91,43 +96,52 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
91 @Override 96 @Override
92 public void process(RequestEvent evt) { 97 public void process(RequestEvent evt) {
93 try { 98 try {
94 - responseAck((SIPRequest) evt.getRequest(), Response.OK, null, null); 99 +
  100 + if (taskQueue.size() >= userSetting.getMaxNotifyCountQueue()) {
  101 + responseAck((SIPRequest) evt.getRequest(), Response.BUSY_HERE, null, null);
  102 + logger.error("[notify] 待处理消息队列已满 {},返回486 BUSY_HERE,消息不做处理", userSetting.getMaxNotifyCountQueue());
  103 + return;
  104 + }else {
  105 + responseAck((SIPRequest) evt.getRequest(), Response.OK, null, null);
  106 + }
  107 +
95 }catch (SipException | InvalidArgumentException | ParseException e) { 108 }catch (SipException | InvalidArgumentException | ParseException e) {
96 logger.error("未处理的异常 ", e); 109 logger.error("未处理的异常 ", e);
97 } 110 }
98 boolean runed = !taskQueue.isEmpty(); 111 boolean runed = !taskQueue.isEmpty();
  112 + logger.info("[notify] 待处理消息数量: {}", taskQueue.size());
99 taskQueue.offer(new HandlerCatchData(evt, null, null)); 113 taskQueue.offer(new HandlerCatchData(evt, null, null));
100 if (!runed) { 114 if (!runed) {
101 taskExecutor.execute(()-> { 115 taskExecutor.execute(()-> {
102 - try {  
103 - while (!taskQueue.isEmpty()) {  
104 - try {  
105 - HandlerCatchData take = taskQueue.poll();  
106 - Element rootElement = getRootElement(take.getEvt());  
107 - if (rootElement == null) {  
108 - logger.error("处理NOTIFY消息时未获取到消息体,{}", take.getEvt().getRequest());  
109 - continue;  
110 - }  
111 - String cmd = XmlUtil.getText(rootElement, "CmdType");  
112 -  
113 - if (CmdType.CATALOG.equals(cmd)) {  
114 - logger.info("接收到Catalog通知");  
115 - processNotifyCatalogList(take.getEvt());  
116 - } else if (CmdType.ALARM.equals(cmd)) {  
117 - logger.info("接收到Alarm通知");  
118 - processNotifyAlarm(take.getEvt());  
119 - } else if (CmdType.MOBILE_POSITION.equals(cmd)) {  
120 - logger.info("接收到MobilePosition通知");  
121 - processNotifyMobilePosition(take.getEvt());  
122 - } else {  
123 - logger.info("接收到消息:" + cmd);  
124 - }  
125 - } catch (DocumentException e) {  
126 - logger.error("处理NOTIFY消息时错误", e); 116 + while (!taskQueue.isEmpty()) {
  117 + try {
  118 + HandlerCatchData take = taskQueue.poll();
  119 + if (take == null) {
  120 + continue;
  121 + }
  122 + Element rootElement = getRootElement(take.getEvt());
  123 + if (rootElement == null) {
  124 + logger.error("处理NOTIFY消息时未获取到消息体,{}", take.getEvt().getRequest());
  125 + continue;
  126 + }
  127 + String cmd = XmlUtil.getText(rootElement, "CmdType");
  128 +
  129 + if (CmdType.CATALOG.equals(cmd)) {
  130 + logger.info("接收到Catalog通知");
  131 +// processNotifyCatalogList(take.getEvt());
  132 + notifyRequestForCatalogProcessor.process(take.getEvt());
  133 + } else if (CmdType.ALARM.equals(cmd)) {
  134 + logger.info("接收到Alarm通知");
  135 + processNotifyAlarm(take.getEvt());
  136 + } else if (CmdType.MOBILE_POSITION.equals(cmd)) {
  137 + logger.info("接收到MobilePosition通知");
  138 + processNotifyMobilePosition(take.getEvt());
  139 + } else {
  140 + logger.info("接收到消息:" + cmd);
127 } 141 }
  142 + } catch (DocumentException e) {
  143 + logger.error("处理NOTIFY消息时错误", e);
128 } 144 }
129 - }catch (Exception e) {  
130 - logger.error("处理NOTIFY消息时错误", e);  
131 } 145 }
132 }); 146 });
133 } 147 }
@@ -135,7 +149,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -135,7 +149,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
135 149
136 /** 150 /**
137 * 处理MobilePosition移动位置Notify 151 * 处理MobilePosition移动位置Notify
138 - * 152 + *
139 * @param evt 153 * @param evt
140 */ 154 */
141 private void processNotifyMobilePosition(RequestEvent evt) { 155 private void processNotifyMobilePosition(RequestEvent evt) {
@@ -239,7 +253,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -239,7 +253,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
239 253
240 /*** 254 /***
241 * 处理alarm设备报警Notify 255 * 处理alarm设备报警Notify
242 - * 256 + *
243 * @param evt 257 * @param evt
244 */ 258 */
245 private void processNotifyAlarm(RequestEvent evt) { 259 private void processNotifyAlarm(RequestEvent evt) {
@@ -349,7 +363,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -349,7 +363,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
349 363
350 /*** 364 /***
351 * 处理catalog设备目录列表Notify 365 * 处理catalog设备目录列表Notify
352 - * 366 + *
353 * @param evt 367 * @param evt
354 */ 368 */
355 private void processNotifyCatalogList(RequestEvent evt) { 369 private void processNotifyCatalogList(RequestEvent evt) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -83,21 +83,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -83,21 +83,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
83 public void process(RequestEvent evt) { 83 public void process(RequestEvent evt) {
84 try { 84 try {
85 RequestEventExt evtExt = (RequestEventExt) evt; 85 RequestEventExt evtExt = (RequestEventExt) evt;
86 - String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();  
87 -  
88 -// MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();  
89 -// QueryExp protocol = Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"));  
90 -//// ObjectName name = new ObjectName("*:type=Connector,*");  
91 -// ObjectName name = new ObjectName("*:*");  
92 -// Set<ObjectName> objectNames = beanServer.queryNames(name, protocol);  
93 -// for (ObjectName objectName : objectNames) {  
94 -// String catalina = objectName.getDomain();  
95 -// if ("Catalina".equals(catalina)) {  
96 -// System.out.println(objectName.getKeyProperty("port"));  
97 -// }  
98 -// }  
99 -  
100 -// System.out.println(ServiceInfo.getServerPort()); 86 +
101 SIPRequest request = (SIPRequest)evt.getRequest(); 87 SIPRequest request = (SIPRequest)evt.getRequest();
102 Response response = null; 88 Response response = null;
103 boolean passwordCorrect = false; 89 boolean passwordCorrect = false;
@@ -107,12 +93,13 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -107,12 +93,13 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
107 AddressImpl address = (AddressImpl) fromHeader.getAddress(); 93 AddressImpl address = (AddressImpl) fromHeader.getAddress();
108 SipUri uri = (SipUri) address.getURI(); 94 SipUri uri = (SipUri) address.getURI();
109 String deviceId = uri.getUser(); 95 String deviceId = uri.getUser();
110 - logger.info("[注册请求] 设备:{}, 开始处理: {}", deviceId, requestAddress); 96 +
111 Device device = deviceService.getDevice(deviceId); 97 Device device = deviceService.getDevice(deviceId);
112 98
113 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, 99 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,
114 userSetting.getSipUseSourceIpAsRemoteAddress()); 100 userSetting.getSipUseSourceIpAsRemoteAddress());
115 - 101 + String requestAddress = remoteAddressInfo.getIp() + ":" + remoteAddressInfo.getPort();
  102 + logger.info("[注册请求] 设备:{}, 开始处理: {}", deviceId, requestAddress);
116 if (device != null && 103 if (device != null &&
117 device.getSipTransactionInfo() != null && 104 device.getSipTransactionInfo() != null &&
118 request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) { 105 request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info;
2 2
3 -import com.genersoft.iot.vmp.common.StreamInfo; 3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.gb28181.bean.*; 5 import com.genersoft.iot.vmp.gb28181.bean.*;
5 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 6 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 7 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
@@ -9,6 +10,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; @@ -9,6 +10,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
9 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; 10 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
10 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
11 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 12 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  13 +import com.genersoft.iot.vmp.service.IInviteStreamService;
12 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 14 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 15 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
14 import gov.nist.javax.sip.message.SIPRequest; 16 import gov.nist.javax.sip.message.SIPRequest;
@@ -17,10 +19,12 @@ import org.slf4j.LoggerFactory; @@ -17,10 +19,12 @@ import org.slf4j.LoggerFactory;
17 import org.springframework.beans.factory.InitializingBean; 19 import org.springframework.beans.factory.InitializingBean;
18 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.stereotype.Component; 21 import org.springframework.stereotype.Component;
  22 +
20 import javax.sip.InvalidArgumentException; 23 import javax.sip.InvalidArgumentException;
21 import javax.sip.RequestEvent; 24 import javax.sip.RequestEvent;
22 import javax.sip.SipException; 25 import javax.sip.SipException;
23 -import javax.sip.header.*; 26 +import javax.sip.header.CallIdHeader;
  27 +import javax.sip.header.ContentTypeHeader;
24 import javax.sip.message.Response; 28 import javax.sip.message.Response;
25 import java.text.ParseException; 29 import java.text.ParseException;
26 30
@@ -44,6 +48,9 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I @@ -44,6 +48,9 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I
44 private IRedisCatchStorage redisCatchStorage; 48 private IRedisCatchStorage redisCatchStorage;
45 49
46 @Autowired 50 @Autowired
  51 + private IInviteStreamService inviteStreamService;
  52 +
  53 + @Autowired
47 private IVideoManagerStorage storager; 54 private IVideoManagerStorage storager;
48 55
49 @Autowired 56 @Autowired
@@ -103,27 +110,30 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I @@ -103,27 +110,30 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I
103 if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) { 110 if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) {
104 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); 111 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
105 String streamId = sendRtpItem.getStream(); 112 String streamId = sendRtpItem.getStream();
106 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
107 - if (null == streamInfo) { 113 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  114 + if (null == inviteInfo) {
108 responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found"); 115 responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found");
109 return; 116 return;
110 } 117 }
111 - Device device1 = storager.queryVideoDevice(streamInfo.getDeviceID());  
112 - cmder.playbackControlCmd(device1,streamInfo,new String(evt.getRequest().getRawContent()),eventResult -> {  
113 - // 失败的回复  
114 - try {  
115 - responseAck(request, eventResult.statusCode, eventResult.msg);  
116 - } catch (SipException | InvalidArgumentException | ParseException e) {  
117 - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());  
118 - }  
119 - }, eventResult -> {  
120 - // 成功的回复  
121 - try {  
122 - responseAck(request, eventResult.statusCode);  
123 - } catch (SipException | InvalidArgumentException | ParseException e) {  
124 - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());  
125 - }  
126 - }); 118 + Device device1 = storager.queryVideoDevice(inviteInfo.getDeviceId());
  119 + if (inviteInfo.getStreamInfo() != null) {
  120 + cmder.playbackControlCmd(device1,inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()),eventResult -> {
  121 + // 失败的回复
  122 + try {
  123 + responseAck(request, eventResult.statusCode, eventResult.msg);
  124 + } catch (SipException | InvalidArgumentException | ParseException e) {
  125 + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
  126 + }
  127 + }, eventResult -> {
  128 + // 成功的回复
  129 + try {
  130 + responseAck(request, eventResult.statusCode);
  131 + } catch (SipException | InvalidArgumentException | ParseException e) {
  132 + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
  133 + }
  134 + });
  135 + }
  136 +
127 } 137 }
128 } 138 }
129 } catch (SipException e) { 139 } catch (SipException e) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -69,6 +69,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp @@ -69,6 +69,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
69 69
70 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); 70 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress());
71 if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { 71 if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) {
  72 + logger.info("[心跳] 设备{}地址变化, 远程地址为: {}:{}", device.getDeviceId(), remoteAddressInfo.getIp(), remoteAddressInfo.getPort());
72 device.setPort(remoteAddressInfo.getPort()); 73 device.setPort(remoteAddressInfo.getPort());
73 device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); 74 device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort())));
74 device.setIp(remoteAddressInfo.getIp()); 75 device.setIp(remoteAddressInfo.getIp());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
2 2
3 -import com.genersoft.iot.vmp.common.StreamInfo; 3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 5 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 import com.genersoft.iot.vmp.gb28181.bean.Device; 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 7 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
@@ -12,6 +13,10 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; @@ -12,6 +13,10 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; 14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; 15 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
  16 +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  17 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  18 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  19 +import com.genersoft.iot.vmp.service.IInviteStreamService;
15 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
16 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 21 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
17 import gov.nist.javax.sip.message.SIPRequest; 22 import gov.nist.javax.sip.message.SIPRequest;
@@ -58,6 +63,15 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -58,6 +63,15 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
58 @Autowired 63 @Autowired
59 private VideoStreamSessionManager sessionManager; 64 private VideoStreamSessionManager sessionManager;
60 65
  66 + @Autowired
  67 + private ZlmHttpHookSubscribe subscribe;
  68 +
  69 + @Autowired
  70 + private IInviteStreamService inviteStreamService;
  71 +
  72 + @Autowired
  73 + private VideoStreamSessionManager streamSession;
  74 +
61 @Override 75 @Override
62 public void afterPropertiesSet() throws Exception { 76 public void afterPropertiesSet() throws Exception {
63 notifyMessageHandler.addHandler(cmdType, this); 77 notifyMessageHandler.addHandler(cmdType, this);
@@ -76,23 +90,24 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -76,23 +90,24 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
76 String NotifyType =getText(rootElement, "NotifyType"); 90 String NotifyType =getText(rootElement, "NotifyType");
77 if ("121".equals(NotifyType)){ 91 if ("121".equals(NotifyType)){
78 logger.info("[录像流]推送完毕,收到关流通知"); 92 logger.info("[录像流]推送完毕,收到关流通知");
79 - // 查询是设备  
80 - StreamInfo streamInfo = redisCatchStorage.queryDownload(null, null, null, callIdHeader.getCallId());  
81 - if (streamInfo != null) {  
82 - // 设置进度100%  
83 - streamInfo.setProgress(1);  
84 - redisCatchStorage.startDownload(streamInfo, callIdHeader.getCallId());  
85 - }  
86 93
87 - // 先从会话内查找  
88 - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);  
89 - if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题 94 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
  95 + if (ssrcTransaction != null) {
  96 + logger.info("[录像流]推送完毕,关流通知, device: {}, channelId: {}", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId());
  97 + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  98 + if (inviteInfo.getStreamInfo() != null) {
  99 + inviteInfo.getStreamInfo().setProgress(1);
  100 + inviteStreamService.updateInviteInfo(inviteInfo);
  101 + }
90 102
91 try { 103 try {
92 cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); 104 cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId());
93 } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { 105 } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
94 logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage()); 106 logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage());
95 } 107 }
  108 + // 去除监听流注销自动停止下载的监听
  109 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcTransaction.getStream(), false, "rtsp", ssrcTransaction.getMediaServerId());
  110 + subscribe.removeSubscribe(hookSubscribe);
96 111
97 // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定 112 // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定
98 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null); 113 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null);
@@ -108,6 +123,8 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -108,6 +123,8 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
108 logger.error("[命令发送失败] 国标级联 录像播放完毕: {}", e.getMessage()); 123 logger.error("[命令发送失败] 国标级联 录像播放完毕: {}", e.getMessage());
109 } 124 }
110 } 125 }
  126 + }else {
  127 + logger.info("[录像流]推送完毕,关流通知, 但是未找到对应的下载信息");
111 } 128 }
112 } 129 }
113 } 130 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
@@ -18,6 +18,10 @@ import javax.sdp.SessionDescription; @@ -18,6 +18,10 @@ import javax.sdp.SessionDescription;
18 import javax.sip.InvalidArgumentException; 18 import javax.sip.InvalidArgumentException;
19 import javax.sip.ResponseEvent; 19 import javax.sip.ResponseEvent;
20 import javax.sip.SipException; 20 import javax.sip.SipException;
  21 +import javax.sip.InvalidArgumentException;
  22 +import javax.sip.ResponseEvent;
  23 +import javax.sip.SipException;
  24 +import javax.sip.SipFactory;
21 import javax.sip.address.SipURI; 25 import javax.sip.address.SipURI;
22 import javax.sip.message.Request; 26 import javax.sip.message.Request;
23 import javax.sip.message.Response; 27 import javax.sip.message.Response;
@@ -91,7 +95,7 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { @@ -91,7 +95,7 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract {
91 } 95 }
92 // 查看是否是来自设备的,此是回复 96 // 查看是否是来自设备的,此是回复
93 97
94 - SipURI requestUri = sipLayer.getSipFactory().createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort()); 98 + SipURI requestUri = SipFactory.getInstance().createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort());
95 Request reqAck = headerProvider.createAckRequest(response.getLocalAddress().getHostAddress(), requestUri, response); 99 Request reqAck = headerProvider.createAckRequest(response.getLocalAddress().getHostAddress(), requestUri, response);
96 100
97 logger.info("[回复ack] {}-> {}:{} ", sdp.getOrigin().getUsername(), event.getRemoteIpAddress(), event.getRemotePort()); 101 logger.info("[回复ack] {}-> {}:{} ", sdp.getOrigin().getUsername(), event.getRemoteIpAddress(), event.getRemotePort());
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
@@ -54,7 +54,7 @@ public class SipUtils { @@ -54,7 +54,7 @@ public class SipUtils {
54 return "z9hG4bK" + System.currentTimeMillis(); 54 return "z9hG4bK" + System.currentTimeMillis();
55 } 55 }
56 56
57 - public static UserAgentHeader createUserAgentHeader(SipFactory sipFactory, GitUtil gitUtil) throws PeerUnavailableException, ParseException { 57 + public static UserAgentHeader createUserAgentHeader(GitUtil gitUtil) throws PeerUnavailableException, ParseException {
58 List<String> agentParam = new ArrayList<>(); 58 List<String> agentParam = new ArrayList<>();
59 agentParam.add("WVP-Pro "); 59 agentParam.add("WVP-Pro ");
60 if (gitUtil != null ) { 60 if (gitUtil != null ) {
@@ -66,7 +66,7 @@ public class SipUtils { @@ -66,7 +66,7 @@ public class SipUtils {
66 agentParam.add(gitUtil.getCommitTime()); 66 agentParam.add(gitUtil.getCommitTime());
67 } 67 }
68 } 68 }
69 - return sipFactory.createHeaderFactory().createUserAgentHeader(agentParam); 69 + return SipFactory.getInstance().createHeaderFactory().createUserAgentHeader(agentParam);
70 } 70 }
71 71
72 public static String getNewFromTag(){ 72 public static String getNewFromTag(){
@@ -153,8 +153,9 @@ public class SipUtils { @@ -153,8 +153,9 @@ public class SipUtils {
153 String remoteAddress; 153 String remoteAddress;
154 int remotePort; 154 int remotePort;
155 if (sipUseSourceIpAsRemoteAddress) { 155 if (sipUseSourceIpAsRemoteAddress) {
156 - remoteAddress = request.getRemoteAddress().getHostAddress();  
157 - remotePort = request.getRemotePort(); 156 + remoteAddress = request.getPeerPacketSourceAddress().getHostAddress();
  157 + remotePort = request.getPeerPacketSourcePort();
  158 +
158 }else { 159 }else {
159 // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息 160 // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息
160 // 获取到通信地址等信息 161 // 获取到通信地址等信息
@@ -162,8 +163,8 @@ public class SipUtils { @@ -162,8 +163,8 @@ public class SipUtils {
162 remotePort = request.getTopmostViaHeader().getRPort(); 163 remotePort = request.getTopmostViaHeader().getRPort();
163 // 解析本地地址替代 164 // 解析本地地址替代
164 if (ObjectUtils.isEmpty(remoteAddress) || remotePort == -1) { 165 if (ObjectUtils.isEmpty(remoteAddress) || remotePort == -1) {
165 - remoteAddress = request.getTopmostViaHeader().getHost();  
166 - remotePort = request.getTopmostViaHeader().getPort(); 166 + remoteAddress = request.getPeerPacketSourceAddress().getHostAddress();
  167 + remotePort = request.getPeerPacketSourcePort();
167 } 168 }
168 } 169 }
169 170
src/main/java/com/genersoft/iot/vmp/jt1078/annotation/MsgId.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.annotation;
  2 +
  3 +import java.lang.annotation.*;
  4 +
  5 +/**
  6 + * @author QingtaiJiang
  7 + * @date 2023/4/27 18:31
  8 + * @email qingtaij@163.com
  9 + */
  10 +@Target(ElementType.TYPE)
  11 +@Retention(RetentionPolicy.RUNTIME)
  12 +@Documented
  13 +public @interface MsgId {
  14 + String id();
  15 +}
src/main/java/com/genersoft/iot/vmp/jt1078/cmd/JT1078Template.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.cmd;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.proc.entity.Cmd;
  4 +import com.genersoft.iot.vmp.jt1078.proc.response.*;
  5 +import com.genersoft.iot.vmp.jt1078.session.SessionManager;
  6 +
  7 +import java.util.Random;
  8 +
  9 +/**
  10 + * @author QingtaiJiang
  11 + * @date 2023/4/27 18:58
  12 + * @email qingtaij@163.com
  13 + */
  14 +public class JT1078Template {
  15 +
  16 + private final Random random = new Random();
  17 +
  18 + private static final String H9101 = "9101";
  19 + private static final String H9102 = "9102";
  20 + private static final String H9201 = "9201";
  21 + private static final String H9202 = "9202";
  22 + private static final String H9205 = "9205";
  23 +
  24 + private static final String H0001 = "0001";
  25 + private static final String H1205 = "1205";
  26 +
  27 + /**
  28 + * 开启直播视频
  29 + *
  30 + * @param devId 设备号
  31 + * @param j9101 开启视频参数
  32 + */
  33 + public String startLive(String devId, J9101 j9101, Integer timeOut) {
  34 + Cmd cmd = new Cmd.Builder()
  35 + .setDevId(devId)
  36 + .setPackageNo(randomInt())
  37 + .setMsgId(H9101)
  38 + .setRespId(H0001)
  39 + .setRs(j9101)
  40 + .build();
  41 + return SessionManager.INSTANCE.request(cmd, timeOut);
  42 + }
  43 +
  44 + /**
  45 + * 关闭直播视频
  46 + *
  47 + * @param devId 设备号
  48 + * @param j9102 关闭视频参数
  49 + */
  50 + public String stopLive(String devId, J9102 j9102, Integer timeOut) {
  51 + Cmd cmd = new Cmd.Builder()
  52 + .setDevId(devId)
  53 + .setPackageNo(randomInt())
  54 + .setMsgId(H9102)
  55 + .setRespId(H0001)
  56 + .setRs(j9102)
  57 + .build();
  58 + return SessionManager.INSTANCE.request(cmd, timeOut);
  59 + }
  60 +
  61 + /**
  62 + * 查询音视频列表
  63 + *
  64 + * @param devId 设备号
  65 + * @param j9205 查询音视频列表
  66 + */
  67 + public String queryBackTime(String devId, J9205 j9205, Integer timeOut) {
  68 + Cmd cmd = new Cmd.Builder()
  69 + .setDevId(devId)
  70 + .setPackageNo(randomInt())
  71 + .setMsgId(H9205)
  72 + .setRespId(H1205)
  73 + .setRs(j9205)
  74 + .build();
  75 + return SessionManager.INSTANCE.request(cmd, timeOut);
  76 + }
  77 +
  78 + /**
  79 + * 开启视频回放
  80 + *
  81 + * @param devId 设备号
  82 + * @param j9201 视频回放参数
  83 + */
  84 + public String startBackLive(String devId, J9201 j9201, Integer timeOut) {
  85 + Cmd cmd = new Cmd.Builder()
  86 + .setDevId(devId)
  87 + .setPackageNo(randomInt())
  88 + .setMsgId(H9201)
  89 + .setRespId(H1205)
  90 + .setRs(j9201)
  91 + .build();
  92 + return SessionManager.INSTANCE.request(cmd, timeOut);
  93 + }
  94 +
  95 + /**
  96 + * 视频回放控制
  97 + *
  98 + * @param devId 设备号
  99 + * @param j9202 控制视频回放参数
  100 + */
  101 + public String controlBackLive(String devId, J9202 j9202, Integer timeOut) {
  102 + Cmd cmd = new Cmd.Builder()
  103 + .setDevId(devId)
  104 + .setPackageNo(randomInt())
  105 + .setMsgId(H9202)
  106 + .setRespId(H0001)
  107 + .setRs(j9202)
  108 + .build();
  109 + return SessionManager.INSTANCE.request(cmd, timeOut);
  110 + }
  111 +
  112 + private Long randomInt() {
  113 + return (long) random.nextInt(1000) + 1;
  114 + }
  115 +}
src/main/java/com/genersoft/iot/vmp/jt1078/codec/decode/Jt808Decoder.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.codec.decode;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  4 +import com.genersoft.iot.vmp.jt1078.proc.factory.CodecFactory;
  5 +import com.genersoft.iot.vmp.jt1078.proc.request.Re;
  6 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  7 +import com.genersoft.iot.vmp.jt1078.session.Session;
  8 +import io.netty.buffer.ByteBuf;
  9 +import io.netty.buffer.ByteBufUtil;
  10 +import io.netty.buffer.CompositeByteBuf;
  11 +import io.netty.buffer.UnpooledByteBufAllocator;
  12 +import io.netty.channel.ChannelHandlerContext;
  13 +import io.netty.handler.codec.ByteToMessageDecoder;
  14 +import org.slf4j.Logger;
  15 +import org.slf4j.LoggerFactory;
  16 +
  17 +import java.util.ArrayList;
  18 +import java.util.List;
  19 +
  20 +/**
  21 + * @author QingtaiJiang
  22 + * @date 2023/4/27 18:10
  23 + * @email qingtaij@163.com
  24 + */
  25 +public class Jt808Decoder extends ByteToMessageDecoder {
  26 + private final static Logger log = LoggerFactory.getLogger(Jt808Decoder.class);
  27 +
  28 + @Override
  29 + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
  30 + Session session = ctx.channel().attr(Session.KEY).get();
  31 + log.info("> {} hex:{}", session, ByteBufUtil.hexDump(in));
  32 +
  33 + try {
  34 + ByteBuf buf = unEscapeAndCheck(in);
  35 +
  36 + Header header = new Header();
  37 + header.setMsgId(ByteBufUtil.hexDump(buf.readSlice(2)));
  38 + header.setMsgPro(buf.readUnsignedShort());
  39 + if (header.is2019Version()) {
  40 + header.setVersion(buf.readUnsignedByte());
  41 + String devId = ByteBufUtil.hexDump(buf.readSlice(10));
  42 + header.setDevId(devId.replaceFirst("^0*", ""));
  43 + } else {
  44 + header.setDevId(ByteBufUtil.hexDump(buf.readSlice(6)).replaceFirst("^0*", ""));
  45 + }
  46 + header.setSn(buf.readUnsignedShort());
  47 +
  48 + Re handler = CodecFactory.getHandler(header.getMsgId());
  49 + if (handler == null) {
  50 + log.error("get msgId is null {}", header.getMsgId());
  51 + return;
  52 + }
  53 + Rs decode = handler.decode(buf, header, session);
  54 + if (decode != null) {
  55 + out.add(decode);
  56 + }
  57 + } finally {
  58 + in.skipBytes(in.readableBytes());
  59 + }
  60 +
  61 +
  62 + }
  63 +
  64 +
  65 + /**
  66 + * 转义与验证校验码
  67 + *
  68 + * @param byteBuf 转义Buf
  69 + * @return 转义好的数据
  70 + */
  71 + public ByteBuf unEscapeAndCheck(ByteBuf byteBuf) throws Exception {
  72 + int low = byteBuf.readerIndex();
  73 + int high = byteBuf.writerIndex();
  74 + byte checkSum = 0;
  75 + int calculationCheckSum = 0;
  76 +
  77 + byte aByte = byteBuf.getByte(high - 2);
  78 + byte protocolEscapeFlag7d = 0x7d;
  79 + //0x7d转义
  80 + byte protocolEscapeFlag01 = 0x01;
  81 + //0x7e转义
  82 + byte protocolEscapeFlag02 = 0x02;
  83 + if (aByte == protocolEscapeFlag7d) {
  84 + byte b2 = byteBuf.getByte(high - 1);
  85 + if (b2 == protocolEscapeFlag01) {
  86 + checkSum = protocolEscapeFlag7d;
  87 + } else if (b2 == protocolEscapeFlag02) {
  88 + checkSum = 0x7e;
  89 + } else {
  90 + log.error("转义1异常:{}", ByteBufUtil.hexDump(byteBuf));
  91 + throw new Exception("转义错误");
  92 + }
  93 + high = high - 2;
  94 + } else {
  95 + high = high - 1;
  96 + checkSum = byteBuf.getByte(high);
  97 + }
  98 + List<ByteBuf> bufList = new ArrayList<>();
  99 + int index = low;
  100 + while (index < high) {
  101 + byte b = byteBuf.getByte(index);
  102 + if (b == protocolEscapeFlag7d) {
  103 + byte c = byteBuf.getByte(index + 1);
  104 + if (c == protocolEscapeFlag01) {
  105 + ByteBuf slice = slice0x01(byteBuf, low, index);
  106 + bufList.add(slice);
  107 + b = protocolEscapeFlag7d;
  108 + } else if (c == protocolEscapeFlag02) {
  109 + ByteBuf slice = slice0x02(byteBuf, low, index);
  110 + bufList.add(slice);
  111 + b = 0x7e;
  112 + } else {
  113 + log.error("转义2异常:{}", ByteBufUtil.hexDump(byteBuf));
  114 + throw new Exception("转义错误");
  115 + }
  116 + index += 2;
  117 + low = index;
  118 + } else {
  119 + index += 1;
  120 + }
  121 + calculationCheckSum = calculationCheckSum ^ b;
  122 + }
  123 +
  124 + if (calculationCheckSum == checkSum) {
  125 + if (bufList.size() == 0) {
  126 + return byteBuf.slice(low, high);
  127 + } else {
  128 + bufList.add(byteBuf.slice(low, high - low));
  129 + return new CompositeByteBuf(UnpooledByteBufAllocator.DEFAULT, false, bufList.size(), bufList);
  130 + }
  131 + } else {
  132 + log.info("{} 解析校验码:{}--计算校验码:{}", ByteBufUtil.hexDump(byteBuf), checkSum, calculationCheckSum);
  133 + throw new Exception("校验码错误!");
  134 + }
  135 + }
  136 +
  137 +
  138 + private ByteBuf slice0x01(ByteBuf buf, int low, int sign) {
  139 + return buf.slice(low, sign - low + 1);
  140 + }
  141 +
  142 + private ByteBuf slice0x02(ByteBuf buf, int low, int sign) {
  143 + buf.setByte(sign, 0x7e);
  144 + return buf.slice(low, sign - low + 1);
  145 + }
  146 +}
src/main/java/com/genersoft/iot/vmp/jt1078/codec/encode/Jt808Encoder.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.codec.encode;
  2 +
  3 +
  4 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  5 +import com.genersoft.iot.vmp.jt1078.session.Session;
  6 +import io.netty.buffer.ByteBuf;
  7 +import io.netty.buffer.ByteBufUtil;
  8 +import io.netty.channel.ChannelHandlerContext;
  9 +import io.netty.handler.codec.MessageToByteEncoder;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
  12 +
  13 +/**
  14 + * @author QingtaiJiang
  15 + * @date 2023/4/27 18:10
  16 + * @email qingtaij@163.com
  17 + */
  18 +public class Jt808Encoder extends MessageToByteEncoder<Rs> {
  19 + private final static Logger log = LoggerFactory.getLogger(Jt808Encoder.class);
  20 +
  21 + @Override
  22 + protected void encode(ChannelHandlerContext ctx, Rs msg, ByteBuf out) throws Exception {
  23 + Session session = ctx.channel().attr(Session.KEY).get();
  24 +
  25 + ByteBuf encode = Jt808EncoderCmd.encode(msg, session, session.nextSerialNo());
  26 + if(encode!=null){
  27 + log.info("< {} hex:{}", session, ByteBufUtil.hexDump(encode));
  28 + out.writeBytes(encode);
  29 + }
  30 + }
  31 +
  32 +
  33 +}
src/main/java/com/genersoft/iot/vmp/jt1078/codec/encode/Jt808EncoderCmd.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.codec.encode;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  5 +import com.genersoft.iot.vmp.jt1078.proc.entity.Cmd;
  6 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  7 +import com.genersoft.iot.vmp.jt1078.session.Session;
  8 +import com.genersoft.iot.vmp.jt1078.util.Bin;
  9 +import io.netty.buffer.ByteBuf;
  10 +import io.netty.buffer.ByteBufUtil;
  11 +import io.netty.buffer.CompositeByteBuf;
  12 +import io.netty.buffer.Unpooled;
  13 +import io.netty.channel.ChannelHandlerContext;
  14 +import io.netty.handler.codec.MessageToByteEncoder;
  15 +import io.netty.util.ByteProcessor;
  16 +import org.slf4j.Logger;
  17 +import org.slf4j.LoggerFactory;
  18 +import org.springframework.util.StringUtils;
  19 +
  20 +import java.util.LinkedList;
  21 +
  22 +/**
  23 + * @author QingtaiJiang
  24 + * @date 2023/4/27 18:25
  25 + * @email qingtaij@163.com
  26 + */
  27 +public class Jt808EncoderCmd extends MessageToByteEncoder<Cmd> {
  28 + private final static Logger log = LoggerFactory.getLogger(Jt808EncoderCmd.class);
  29 +
  30 + @Override
  31 + protected void encode(ChannelHandlerContext ctx, Cmd cmd, ByteBuf out) throws Exception {
  32 + Session session = ctx.channel().attr(Session.KEY).get();
  33 + Rs msg = cmd.getRs();
  34 + ByteBuf encode = encode(msg, session, cmd.getPackageNo().intValue());
  35 + if (encode != null) {
  36 + log.info("< {} hex:{}", session, ByteBufUtil.hexDump(encode));
  37 + out.writeBytes(encode);
  38 + }
  39 + }
  40 +
  41 +
  42 + public static ByteBuf encode(Rs msg, Session session, Integer packageNo) {
  43 + String id = msg.getClass().getAnnotation(MsgId.class).id();
  44 + if (!StringUtils.hasLength(id)) {
  45 + log.error("Not find msgId");
  46 + return null;
  47 + }
  48 +
  49 + ByteBuf byteBuf = Unpooled.buffer();
  50 +
  51 + byteBuf.writeBytes(ByteBufUtil.decodeHexDump(id));
  52 +
  53 + ByteBuf encode = msg.encode();
  54 +
  55 + Header header = msg.getHeader();
  56 + if (header == null) {
  57 + header = session.getHeader();
  58 + }
  59 +
  60 + if (header.is2019Version()) {
  61 + // 消息体属性
  62 + byteBuf.writeShort(encode.readableBytes() | 1 << 14);
  63 +
  64 + // 版本号
  65 + byteBuf.writeByte(header.getVersion());
  66 +
  67 + // 终端手机号
  68 + byteBuf.writeBytes(ByteBufUtil.decodeHexDump(Bin.strHexPaddingLeft(header.getDevId(), 20)));
  69 + } else {
  70 + // 消息体属性
  71 + byteBuf.writeShort(encode.readableBytes());
  72 +
  73 + byteBuf.writeBytes(ByteBufUtil.decodeHexDump(Bin.strHexPaddingLeft(header.getDevId(), 12)));
  74 + }
  75 +
  76 + // 消息体流水号
  77 + byteBuf.writeShort(packageNo);
  78 +
  79 + // 写入消息体
  80 + byteBuf.writeBytes(encode);
  81 +
  82 + // 计算校验码,并反转义
  83 + byteBuf = escapeAndCheck0(byteBuf);
  84 + return byteBuf;
  85 + }
  86 +
  87 +
  88 + private static final ByteProcessor searcher = value -> !(value == 0x7d || value == 0x7e);
  89 +
  90 + //转义与校验
  91 + public static ByteBuf escapeAndCheck0(ByteBuf source) {
  92 +
  93 + sign(source);
  94 +
  95 + int low = source.readerIndex();
  96 + int high = source.writerIndex();
  97 +
  98 + LinkedList<ByteBuf> bufList = new LinkedList<>();
  99 + int mark, len;
  100 + while ((mark = source.forEachByte(low, high - low, searcher)) > 0) {
  101 +
  102 + len = mark + 1 - low;
  103 + ByteBuf[] slice = slice(source, low, len);
  104 + bufList.add(slice[0]);
  105 + bufList.add(slice[1]);
  106 + low += len;
  107 + }
  108 +
  109 + if (bufList.size() > 0) {
  110 + bufList.add(source.slice(low, high - low));
  111 + } else {
  112 + bufList.add(source);
  113 + }
  114 +
  115 + ByteBuf delimiter = Unpooled.buffer(1, 1).writeByte(0x7e).retain();
  116 + bufList.addFirst(delimiter);
  117 + bufList.addLast(delimiter);
  118 +
  119 + CompositeByteBuf byteBufLs = Unpooled.compositeBuffer(bufList.size());
  120 + byteBufLs.addComponents(true, bufList);
  121 + return byteBufLs;
  122 + }
  123 +
  124 + public static void sign(ByteBuf buf) {
  125 + byte checkCode = bcc(buf);
  126 + buf.writeByte(checkCode);
  127 + }
  128 +
  129 + public static byte bcc(ByteBuf byteBuf) {
  130 + byte cs = 0;
  131 + while (byteBuf.isReadable())
  132 + cs ^= byteBuf.readByte();
  133 + byteBuf.resetReaderIndex();
  134 + return cs;
  135 + }
  136 +
  137 + protected static ByteBuf[] slice(ByteBuf byteBuf, int index, int length) {
  138 + byte first = byteBuf.getByte(index + length - 1);
  139 +
  140 + ByteBuf[] byteBufList = new ByteBuf[2];
  141 + byteBufList[0] = byteBuf.retainedSlice(index, length);
  142 +
  143 + if (first == 0x7d) {
  144 + byteBufList[1] = Unpooled.buffer(1, 1).writeByte(0x01);
  145 + } else {
  146 + byteBuf.setByte(index + length - 1, 0x7d);
  147 + byteBufList[1] = Unpooled.buffer(1, 1).writeByte(0x02);
  148 + }
  149 + return byteBufList;
  150 + }
  151 +}
src/main/java/com/genersoft/iot/vmp/jt1078/codec/netty/Jt808Handler.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.codec.netty;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  4 +import com.genersoft.iot.vmp.jt1078.session.Session;
  5 +import com.genersoft.iot.vmp.jt1078.session.SessionManager;
  6 +import io.netty.channel.Channel;
  7 +import io.netty.channel.ChannelHandlerContext;
  8 +import io.netty.channel.ChannelInboundHandlerAdapter;
  9 +import io.netty.handler.timeout.IdleState;
  10 +import io.netty.handler.timeout.IdleStateEvent;
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
  13 +
  14 +/**
  15 + * @author QingtaiJiang
  16 + * @date 2023/4/27 18:14
  17 + * @email qingtaij@163.com
  18 + */
  19 +public class Jt808Handler extends ChannelInboundHandlerAdapter {
  20 +
  21 + private final static Logger log = LoggerFactory.getLogger(Jt808Handler.class);
  22 +
  23 + @Override
  24 + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  25 + if (msg instanceof Rs) {
  26 + ctx.writeAndFlush(msg);
  27 + } else {
  28 + ctx.fireChannelRead(msg);
  29 + }
  30 + }
  31 +
  32 + @Override
  33 + public void channelActive(ChannelHandlerContext ctx) {
  34 + Channel channel = ctx.channel();
  35 + Session session = SessionManager.INSTANCE.newSession(channel);
  36 + channel.attr(Session.KEY).set(session);
  37 + log.info("> Tcp connect {}", session);
  38 + }
  39 +
  40 + @Override
  41 + public void channelInactive(ChannelHandlerContext ctx) {
  42 + Session session = ctx.channel().attr(Session.KEY).get();
  43 + log.info("< Tcp disconnect {}", session);
  44 + ctx.close();
  45 + }
  46 +
  47 + @Override
  48 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) {
  49 + Session session = ctx.channel().attr(Session.KEY).get();
  50 + String message = e.getMessage();
  51 + if (message.toLowerCase().contains("Connection reset by peer".toLowerCase())) {
  52 + log.info("< exception{} {}", session, e.getMessage());
  53 + } else {
  54 + log.info("< exception{} {}", session, e.getMessage(), e);
  55 + }
  56 +
  57 + }
  58 +
  59 + @Override
  60 + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
  61 + if (evt instanceof IdleStateEvent) {
  62 + IdleStateEvent event = (IdleStateEvent) evt;
  63 + IdleState state = event.state();
  64 + if (state == IdleState.READER_IDLE || state == IdleState.WRITER_IDLE) {
  65 + Session session = ctx.channel().attr(Session.KEY).get();
  66 + log.warn("< Proactively disconnect{}", session);
  67 + ctx.close();
  68 + }
  69 + }
  70 + }
  71 +
  72 +}
src/main/java/com/genersoft/iot/vmp/jt1078/codec/netty/TcpServer.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.codec.netty;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.codec.decode.Jt808Decoder;
  4 +import com.genersoft.iot.vmp.jt1078.codec.encode.Jt808Encoder;
  5 +import com.genersoft.iot.vmp.jt1078.codec.encode.Jt808EncoderCmd;
  6 +import com.genersoft.iot.vmp.jt1078.proc.factory.CodecFactory;
  7 +import io.netty.bootstrap.ServerBootstrap;
  8 +import io.netty.buffer.ByteBuf;
  9 +import io.netty.buffer.Unpooled;
  10 +import io.netty.channel.ChannelFuture;
  11 +import io.netty.channel.ChannelInitializer;
  12 +import io.netty.channel.EventLoopGroup;
  13 +import io.netty.channel.nio.NioEventLoopGroup;
  14 +import io.netty.channel.socket.nio.NioChannelOption;
  15 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  16 +import io.netty.channel.socket.nio.NioSocketChannel;
  17 +import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  18 +import io.netty.handler.timeout.IdleStateHandler;
  19 +import io.netty.util.concurrent.Future;
  20 +import org.slf4j.Logger;
  21 +import org.slf4j.LoggerFactory;
  22 +
  23 +import java.util.concurrent.TimeUnit;
  24 +
  25 +/**
  26 + * @author QingtaiJiang
  27 + * @date 2023/4/27 18:01
  28 + * @email qingtaij@163.com
  29 + */
  30 +
  31 +public class TcpServer {
  32 + private final static Logger log = LoggerFactory.getLogger(TcpServer.class);
  33 +
  34 + private final Integer port;
  35 + private boolean isRunning = false;
  36 + private EventLoopGroup bossGroup = null;
  37 + private EventLoopGroup workerGroup = null;
  38 +
  39 + private final ByteBuf DECODER_JT808 = Unpooled.wrappedBuffer(new byte[]{0x7e});
  40 +
  41 + public TcpServer(Integer port) {
  42 + this.port = port;
  43 + }
  44 +
  45 + private void startTcpServer() {
  46 + try {
  47 + CodecFactory.init();
  48 + this.bossGroup = new NioEventLoopGroup();
  49 + this.workerGroup = new NioEventLoopGroup();
  50 + ServerBootstrap bootstrap = new ServerBootstrap();
  51 + bootstrap.channel(NioServerSocketChannel.class);
  52 + bootstrap.group(bossGroup, workerGroup);
  53 +
  54 + bootstrap.option(NioChannelOption.SO_BACKLOG, 1024)
  55 + .option(NioChannelOption.SO_REUSEADDR, true)
  56 + .childOption(NioChannelOption.TCP_NODELAY, true)
  57 + .childHandler(new ChannelInitializer<NioSocketChannel>() {
  58 + @Override
  59 + public void initChannel(NioSocketChannel channel) {
  60 + channel.pipeline()
  61 + .addLast(new IdleStateHandler(10, 0, 0, TimeUnit.MINUTES))
  62 + .addLast(new DelimiterBasedFrameDecoder(1024 * 2, DECODER_JT808))
  63 + .addLast(new Jt808Decoder())
  64 + .addLast(new Jt808Encoder())
  65 + .addLast(new Jt808EncoderCmd())
  66 + .addLast(new Jt808Handler());
  67 + }
  68 + });
  69 + ChannelFuture channelFuture = bootstrap.bind(port).sync();
  70 + // 监听设备TCP端口是否启动成功
  71 + channelFuture.addListener(future -> {
  72 + if (!future.isSuccess()) {
  73 + log.error("Binding port:{} fail! cause: {}", port, future.cause().getCause(), future.cause());
  74 + }
  75 + });
  76 + log.info("服务:JT808 Server 启动成功, port:{}", port);
  77 + channelFuture.channel().closeFuture().sync();
  78 + } catch (Exception e) {
  79 + log.warn("服务:JT808 Server 启动异常, port:{},{}", port, e.getMessage(), e);
  80 + } finally {
  81 + stop();
  82 + }
  83 + }
  84 +
  85 + /**
  86 + * 开启一个新的线程,拉起来Netty
  87 + */
  88 + public synchronized void start() {
  89 + if (this.isRunning) {
  90 + log.warn("服务:JT808 Server 已经启动, port:{}", port);
  91 + return;
  92 + }
  93 + this.isRunning = true;
  94 + new Thread(this::startTcpServer).start();
  95 + }
  96 +
  97 + public synchronized void stop() {
  98 + if (!this.isRunning) {
  99 + log.warn("服务:JT808 Server 已经停止, port:{}", port);
  100 + }
  101 + this.isRunning = false;
  102 + Future<?> future = this.bossGroup.shutdownGracefully();
  103 + if (!future.isSuccess()) {
  104 + log.warn("bossGroup 无法正常停止", future.cause());
  105 + }
  106 + future = this.workerGroup.shutdownGracefully();
  107 + if (!future.isSuccess()) {
  108 + log.warn("workerGroup 无法正常停止", future.cause());
  109 + }
  110 + log.warn("服务:JT808 Server 已经停止, port:{}", port);
  111 + }
  112 +}
src/main/java/com/genersoft/iot/vmp/jt1078/config/JT1078AutoConfiguration.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.config;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template;
  4 +import com.genersoft.iot.vmp.jt1078.codec.netty.TcpServer;
  5 +import org.springframework.beans.factory.annotation.Value;
  6 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  7 +import org.springframework.context.annotation.Bean;
  8 +import org.springframework.context.annotation.Configuration;
  9 +import org.springframework.core.annotation.Order;
  10 +
  11 +/**
  12 + * @author QingtaiJiang
  13 + * @date 2023/4/27 19:35
  14 + * @email qingtaij@163.com
  15 + */
  16 +@Order(Integer.MIN_VALUE)
  17 +@Configuration
  18 +@ConditionalOnProperty(value = "jt1078.enable", havingValue = "true")
  19 +public class JT1078AutoConfiguration {
  20 +
  21 + @Bean(initMethod = "start", destroyMethod = "stop")
  22 + public TcpServer jt1078Server(@Value("${jt1078.port}") Integer port) {
  23 + return new TcpServer(port);
  24 + }
  25 +
  26 + @Bean
  27 + public JT1078Template jt1078Template() {
  28 + return new JT1078Template();
  29 + }
  30 +}
src/main/java/com/genersoft/iot/vmp/jt1078/config/JT1078Controller.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.config;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template;
  4 +import com.genersoft.iot.vmp.jt1078.proc.response.*;
  5 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
  6 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  7 +import org.springframework.web.bind.annotation.GetMapping;
  8 +import org.springframework.web.bind.annotation.PathVariable;
  9 +import org.springframework.web.bind.annotation.RequestMapping;
  10 +import org.springframework.web.bind.annotation.RestController;
  11 +
  12 +import javax.annotation.Resource;
  13 +
  14 +/**
  15 + * curl http://localhost:18080/api/jt1078/start/live/18864197066/1
  16 + *
  17 + * @author QingtaiJiang
  18 + * @date 2023/4/27 18:12
  19 + * @email qingtaij@163.com
  20 + */
  21 +@ConditionalOnProperty(value = "jt1078.enable", havingValue = "true")
  22 +@RestController
  23 +@RequestMapping("/api/jt1078")
  24 +public class JT1078Controller {
  25 +
  26 + @Resource
  27 + JT1078Template jt1078Template;
  28 +
  29 + /**
  30 + * jt1078Template 调用示例
  31 + */
  32 + @GetMapping("/start/live/{deviceId}/{channelId}")
  33 + public WVPResult<?> startLive(@PathVariable String deviceId, @PathVariable String channelId) {
  34 + J9101 j9101 = new J9101();
  35 + j9101.setChannel(Integer.valueOf(channelId));
  36 + j9101.setIp("192.168.1.1");
  37 + j9101.setRate(1);
  38 + j9101.setTcpPort(7618);
  39 + j9101.setUdpPort(7618);
  40 + j9101.setType(0);
  41 + // TODO 分配ZLM,获取IP、端口
  42 + String s = jt1078Template.startLive(deviceId, j9101, 6);
  43 + // TODO 设备响应成功后,封装拉流结果集
  44 + WVPResult<String> wvpResult = new WVPResult<>();
  45 + wvpResult.setCode(200);
  46 + wvpResult.setData(String.format("http://192.168.1.1/rtp/%s_%s.live.mp4", deviceId, channelId));
  47 + return wvpResult;
  48 + }
  49 +
  50 +}
  51 +
src/main/java/com/genersoft/iot/vmp/jt1078/proc/Header.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.util.Bin;
  4 +
  5 +/**
  6 + * @author QingtaiJiang
  7 + * @date 2023/4/27 18:22
  8 + * @email qingtaij@163.com
  9 + */
  10 +public class Header {
  11 + // 消息ID
  12 + String msgId;
  13 +
  14 + // 消息体属性
  15 + Integer msgPro;
  16 +
  17 + // 标识
  18 + String devId;
  19 +
  20 + // 消息体流水号
  21 + Integer sn;
  22 +
  23 + // 协议版本号
  24 + Short version = -1;
  25 +
  26 +
  27 + public String getMsgId() {
  28 + return msgId;
  29 + }
  30 +
  31 + public void setMsgId(String msgId) {
  32 + this.msgId = msgId;
  33 + }
  34 +
  35 + public Integer getMsgPro() {
  36 + return msgPro;
  37 + }
  38 +
  39 + public void setMsgPro(Integer msgPro) {
  40 + this.msgPro = msgPro;
  41 + }
  42 +
  43 + public String getDevId() {
  44 + return devId;
  45 + }
  46 +
  47 + public void setDevId(String devId) {
  48 + this.devId = devId;
  49 + }
  50 +
  51 + public Integer getSn() {
  52 + return sn;
  53 + }
  54 +
  55 + public void setSn(Integer sn) {
  56 + this.sn = sn;
  57 + }
  58 +
  59 + public Short getVersion() {
  60 + return version;
  61 + }
  62 +
  63 + public void setVersion(Short version) {
  64 + this.version = version;
  65 + }
  66 +
  67 + /**
  68 + * 判断是否是2019的版本
  69 + *
  70 + * @return true 2019后的版本。false 2013
  71 + */
  72 + public boolean is2019Version() {
  73 + return Bin.get(msgPro, 14);
  74 + }
  75 +
  76 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/entity/Cmd.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.entity;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  4 +
  5 +/**
  6 + * @author QingtaiJiang
  7 + * @date 2023/4/27 18:23
  8 + * @email qingtaij@163.com
  9 + */
  10 +public class Cmd {
  11 + String devId;
  12 + Long packageNo;
  13 + String msgId;
  14 + String respId;
  15 + Rs rs;
  16 +
  17 + public Cmd() {
  18 + }
  19 +
  20 + public Cmd(Builder builder) {
  21 + this.devId = builder.devId;
  22 + this.packageNo = builder.packageNo;
  23 + this.msgId = builder.msgId;
  24 + this.respId = builder.respId;
  25 + this.rs = builder.rs;
  26 + }
  27 +
  28 + public String getDevId() {
  29 + return devId;
  30 + }
  31 +
  32 + public void setDevId(String devId) {
  33 + this.devId = devId;
  34 + }
  35 +
  36 + public Long getPackageNo() {
  37 + return packageNo;
  38 + }
  39 +
  40 + public void setPackageNo(Long packageNo) {
  41 + this.packageNo = packageNo;
  42 + }
  43 +
  44 + public String getMsgId() {
  45 + return msgId;
  46 + }
  47 +
  48 + public void setMsgId(String msgId) {
  49 + this.msgId = msgId;
  50 + }
  51 +
  52 + public String getRespId() {
  53 + return respId;
  54 + }
  55 +
  56 + public void setRespId(String respId) {
  57 + this.respId = respId;
  58 + }
  59 +
  60 + public Rs getRs() {
  61 + return rs;
  62 + }
  63 +
  64 + public void setRs(Rs rs) {
  65 + this.rs = rs;
  66 + }
  67 +
  68 + public static class Builder {
  69 + String devId;
  70 + Long packageNo;
  71 + String msgId;
  72 + String respId;
  73 + Rs rs;
  74 +
  75 + public Builder setDevId(String devId) {
  76 + this.devId = devId.replaceFirst("^0*", "");
  77 + return this;
  78 + }
  79 +
  80 + public Builder setPackageNo(Long packageNo) {
  81 + this.packageNo = packageNo;
  82 + return this;
  83 + }
  84 +
  85 + public Builder setMsgId(String msgId) {
  86 + this.msgId = msgId;
  87 + return this;
  88 + }
  89 +
  90 + public Builder setRespId(String respId) {
  91 + this.respId = respId;
  92 + return this;
  93 + }
  94 +
  95 + public Builder setRs(Rs re) {
  96 + this.rs = re;
  97 + return this;
  98 + }
  99 +
  100 + public Cmd build() {
  101 + return new Cmd(this);
  102 + }
  103 + }
  104 +
  105 +
  106 + @Override
  107 + public String toString() {
  108 + return "Cmd{" +
  109 + "devId='" + devId + '\'' +
  110 + ", packageNo=" + packageNo +
  111 + ", msgId='" + msgId + '\'' +
  112 + ", respId='" + respId + '\'' +
  113 + ", rs=" + rs +
  114 + '}';
  115 + }
  116 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/factory/CodecFactory.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.factory;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import com.genersoft.iot.vmp.jt1078.proc.request.Re;
  5 +import com.genersoft.iot.vmp.jt1078.util.ClassUtil;
  6 +import org.slf4j.Logger;
  7 +import org.slf4j.LoggerFactory;
  8 +
  9 +import java.util.HashMap;
  10 +import java.util.List;
  11 +import java.util.Map;
  12 +
  13 +/**
  14 + * @author QingtaiJiang
  15 + * @date 2023/4/27 18:29
  16 + * @email qingtaij@163.com
  17 + */
  18 +
  19 +public class CodecFactory {
  20 + private final static Logger log = LoggerFactory.getLogger(CodecFactory.class);
  21 +
  22 + private static Map<String, Class<?>> protocolHash;
  23 +
  24 + public static void init() {
  25 + protocolHash = new HashMap<>();
  26 + List<Class<?>> classList = ClassUtil.getClassList("com.genersoft.iot.vmp.jt1078.proc", MsgId.class);
  27 + for (Class<?> handlerClass : classList) {
  28 + String id = handlerClass.getAnnotation(MsgId.class).id();
  29 + protocolHash.put(id, handlerClass);
  30 + }
  31 + if (log.isDebugEnabled()) {
  32 + log.debug("消息ID缓存表 protocolHash:{}", protocolHash);
  33 + }
  34 + }
  35 +
  36 + public static Re getHandler(String msgId) {
  37 + Class<?> aClass = protocolHash.get(msgId);
  38 + Object bean = ClassUtil.getBean(aClass);
  39 + if (bean instanceof Re) {
  40 + return (Re) bean;
  41 + }
  42 + return null;
  43 + }
  44 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0001.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.request;
  2 +
  3 +import com.alibaba.fastjson2.JSON;
  4 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  5 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  6 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  7 +import com.genersoft.iot.vmp.jt1078.session.Session;
  8 +import com.genersoft.iot.vmp.jt1078.session.SessionManager;
  9 +import io.netty.buffer.ByteBuf;
  10 +import io.netty.buffer.ByteBufUtil;
  11 +
  12 +/**
  13 + * 终端通用应答
  14 + *
  15 + * @author QingtaiJiang
  16 + * @date 2023/4/27 18:04
  17 + * @email qingtaij@163.com
  18 + */
  19 +@MsgId(id = "0001")
  20 +public class J0001 extends Re {
  21 + int respNo;
  22 + String respId;
  23 + int result;
  24 +
  25 + @Override
  26 + protected Rs decode0(ByteBuf buf, Header header, Session session) {
  27 + respNo = buf.readUnsignedShort();
  28 + respId = ByteBufUtil.hexDump(buf.readSlice(2));
  29 + result = buf.readUnsignedByte();
  30 + return null;
  31 + }
  32 +
  33 + @Override
  34 + protected Rs handler(Header header, Session session) {
  35 + SessionManager.INSTANCE.response(header.getDevId(), "0001", (long) respNo, JSON.toJSONString(this));
  36 + return null;
  37 + }
  38 +
  39 + public int getRespNo() {
  40 + return respNo;
  41 + }
  42 +
  43 + public String getRespId() {
  44 + return respId;
  45 + }
  46 +
  47 + public int getResult() {
  48 + return result;
  49 + }
  50 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0002.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.request;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  5 +import com.genersoft.iot.vmp.jt1078.proc.response.J8001;
  6 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  7 +import com.genersoft.iot.vmp.jt1078.session.Session;
  8 +import io.netty.buffer.ByteBuf;
  9 +
  10 +/**
  11 + * 终端心跳
  12 + *
  13 + * @author QingtaiJiang
  14 + * @date 2023/4/27 18:04
  15 + * @email qingtaij@163.com
  16 + */
  17 +@MsgId(id = "0002")
  18 +public class J0002 extends Re {
  19 + @Override
  20 + protected Rs decode0(ByteBuf buf, Header header, Session session) {
  21 + return null;
  22 + }
  23 +
  24 + @Override
  25 + protected Rs handler(Header header, Session session) {
  26 + J8001 j8001 = new J8001();
  27 + j8001.setRespNo(header.getSn());
  28 + j8001.setRespId(header.getMsgId());
  29 + j8001.setResult(J8001.SUCCESS);
  30 + return j8001;
  31 + }
  32 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0004.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.request;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  5 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  6 +import com.genersoft.iot.vmp.jt1078.session.Session;
  7 +import io.netty.buffer.ByteBuf;
  8 +
  9 +/**
  10 + * 查询服务器时间
  11 + *
  12 + * @author QingtaiJiang
  13 + * @date 2023/4/27 18:06
  14 + * @email qingtaij@163.com
  15 + */
  16 +@MsgId(id = "0004")
  17 +public class J0004 extends Re {
  18 + @Override
  19 + protected Rs decode0(ByteBuf buf, Header header, Session session) {
  20 + return null;
  21 + }
  22 +
  23 + @Override
  24 + protected Rs handler(Header header, Session session) {
  25 + return null;
  26 + }
  27 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0100.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.request;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  5 +import com.genersoft.iot.vmp.jt1078.proc.response.J8100;
  6 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  7 +import com.genersoft.iot.vmp.jt1078.session.Session;
  8 +import io.netty.buffer.ByteBuf;
  9 +
  10 +/**
  11 + * 终端注册
  12 + *
  13 + * @author QingtaiJiang
  14 + * @date 2023/4/27 18:06
  15 + * @email qingtaij@163.com
  16 + */
  17 +@MsgId(id = "0100")
  18 +public class J0100 extends Re {
  19 +
  20 + private int provinceId;
  21 +
  22 + private int cityId;
  23 +
  24 + private String makerId;
  25 +
  26 + private String deviceModel;
  27 +
  28 + private String deviceId;
  29 +
  30 + private int plateColor;
  31 +
  32 + private String plateNo;
  33 +
  34 + @Override
  35 + protected Rs decode0(ByteBuf buf, Header header, Session session) {
  36 + Short version = header.getVersion();
  37 + provinceId = buf.readUnsignedShort();
  38 + if (version > 1) {
  39 + cityId = buf.readUnsignedShort();
  40 + // decode as 2019
  41 + } else {
  42 + int i = buf.readUnsignedShort();
  43 + // decode as 2013
  44 + }
  45 + return null;
  46 + }
  47 +
  48 + @Override
  49 + protected Rs handler(Header header, Session session) {
  50 + J8100 j8100 = new J8100();
  51 + j8100.setRespNo(header.getSn());
  52 + j8100.setResult(J8100.SUCCESS);
  53 + j8100.setCode("WVP_YYDS");
  54 + return j8100;
  55 + }
  56 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0102.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.request;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  5 +import com.genersoft.iot.vmp.jt1078.proc.response.J8001;
  6 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  7 +import com.genersoft.iot.vmp.jt1078.session.Session;
  8 +import io.netty.buffer.ByteBuf;
  9 +
  10 +/**
  11 + * 终端鉴权
  12 + *
  13 + * @author QingtaiJiang
  14 + * @date 2023/4/27 18:06
  15 + * @email qingtaij@163.com
  16 + */
  17 +@MsgId(id = "0102")
  18 +public class J0102 extends Re {
  19 + @Override
  20 + protected Rs decode0(ByteBuf buf, Header header, Session session) {
  21 + int lenCode = buf.readUnsignedByte();
  22 +// String code = buf.readCharSequence(lenCode, CharsetUtil.UTF_8).toString();
  23 + // if 2019 to decode next
  24 + return null;
  25 + }
  26 +
  27 + @Override
  28 + protected Rs handler(Header header, Session session) {
  29 + J8001 j8001 = new J8001();
  30 + j8001.setRespNo(header.getSn());
  31 + j8001.setRespId(header.getMsgId());
  32 + j8001.setResult(J8001.SUCCESS);
  33 + return j8001;
  34 + }
  35 +
  36 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J0200.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.request;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  5 +import com.genersoft.iot.vmp.jt1078.proc.response.J8001;
  6 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  7 +import com.genersoft.iot.vmp.jt1078.session.Session;
  8 +import io.netty.buffer.ByteBuf;
  9 +
  10 +/**
  11 + * 实时消息上报
  12 + *
  13 + * @author QingtaiJiang
  14 + * @date 2023/4/27 18:06
  15 + * @email qingtaij@163.com
  16 + */
  17 +@MsgId(id = "0200")
  18 +public class J0200 extends Re {
  19 + @Override
  20 + protected Rs decode0(ByteBuf buf, Header header, Session session) {
  21 + return null;
  22 + }
  23 +
  24 + @Override
  25 + protected Rs handler(Header header, Session session) {
  26 + J8001 j8001 = new J8001();
  27 + j8001.setRespNo(header.getSn());
  28 + j8001.setRespId(header.getMsgId());
  29 + j8001.setResult(J8001.SUCCESS);
  30 + return j8001;
  31 + }
  32 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/J1205.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.request;
  2 +
  3 +import com.alibaba.fastjson2.JSON;
  4 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  5 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  6 +import com.genersoft.iot.vmp.jt1078.proc.response.J8001;
  7 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  8 +import com.genersoft.iot.vmp.jt1078.session.Session;
  9 +import com.genersoft.iot.vmp.jt1078.session.SessionManager;
  10 +import io.netty.buffer.ByteBuf;
  11 +import io.netty.buffer.ByteBufUtil;
  12 +
  13 +import java.util.ArrayList;
  14 +import java.util.List;
  15 +
  16 +/**
  17 + * 终端上传音视频资源列表
  18 + *
  19 + * @author QingtaiJiang
  20 + * @date 2023/4/28 10:36
  21 + * @email qingtaij@163.com
  22 + */
  23 +@MsgId(id = "1205")
  24 +public class J1205 extends Re {
  25 + Integer respNo;
  26 +
  27 + private List<JRecordItem> recordList = new ArrayList<JRecordItem>();
  28 +
  29 + @Override
  30 + protected Rs decode0(ByteBuf buf, Header header, Session session) {
  31 + respNo = buf.readUnsignedShort();
  32 + long size = buf.readUnsignedInt();
  33 +
  34 + for (int i = 0; i < size; i++) {
  35 + JRecordItem item = new JRecordItem();
  36 + item.setChannelId(buf.readUnsignedByte());
  37 + item.setStartTime(ByteBufUtil.hexDump(buf.readSlice(6)));
  38 + item.setEndTime(ByteBufUtil.hexDump(buf.readSlice(6)));
  39 + item.setWarn(buf.readLong());
  40 + item.setMediaType(buf.readUnsignedByte());
  41 + item.setStreamType(buf.readUnsignedByte());
  42 + item.setStorageType(buf.readUnsignedByte());
  43 + item.setSize(buf.readUnsignedInt());
  44 + recordList.add(item);
  45 + }
  46 +
  47 + return null;
  48 + }
  49 +
  50 + @Override
  51 + protected Rs handler(Header header, Session session) {
  52 + SessionManager.INSTANCE.response(header.getDevId(), "1205", (long) respNo, JSON.toJSONString(this));
  53 +
  54 + J8001 j8001 = new J8001();
  55 + j8001.setRespNo(header.getSn());
  56 + j8001.setRespId(header.getMsgId());
  57 + j8001.setResult(J8001.SUCCESS);
  58 + return j8001;
  59 + }
  60 +
  61 +
  62 + public Integer getRespNo() {
  63 + return respNo;
  64 + }
  65 +
  66 + public void setRespNo(Integer respNo) {
  67 + this.respNo = respNo;
  68 + }
  69 +
  70 + public List<JRecordItem> getRecordList() {
  71 + return recordList;
  72 + }
  73 +
  74 + public void setRecordList(List<JRecordItem> recordList) {
  75 + this.recordList = recordList;
  76 + }
  77 +
  78 + public static class JRecordItem {
  79 +
  80 + // 逻辑通道号
  81 + private int channelId;
  82 +
  83 + // 开始时间
  84 + private String startTime;
  85 +
  86 + // 结束时间
  87 + private String endTime;
  88 +
  89 + // 报警标志
  90 + private long warn;
  91 +
  92 + // 音视频资源类型
  93 + private int mediaType;
  94 +
  95 + // 码流类型
  96 + private int streamType = 1;
  97 +
  98 + // 存储器类型
  99 + private int storageType;
  100 +
  101 + // 文件大小
  102 + private long size;
  103 +
  104 + public int getChannelId() {
  105 + return channelId;
  106 + }
  107 +
  108 + public void setChannelId(int channelId) {
  109 + this.channelId = channelId;
  110 + }
  111 +
  112 + public String getStartTime() {
  113 + return startTime;
  114 + }
  115 +
  116 + public void setStartTime(String startTime) {
  117 + this.startTime = startTime;
  118 + }
  119 +
  120 + public String getEndTime() {
  121 + return endTime;
  122 + }
  123 +
  124 + public void setEndTime(String endTime) {
  125 + this.endTime = endTime;
  126 + }
  127 +
  128 + public long getWarn() {
  129 + return warn;
  130 + }
  131 +
  132 + public void setWarn(long warn) {
  133 + this.warn = warn;
  134 + }
  135 +
  136 + public int getMediaType() {
  137 + return mediaType;
  138 + }
  139 +
  140 + public void setMediaType(int mediaType) {
  141 + this.mediaType = mediaType;
  142 + }
  143 +
  144 + public int getStreamType() {
  145 + return streamType;
  146 + }
  147 +
  148 + public void setStreamType(int streamType) {
  149 + this.streamType = streamType;
  150 + }
  151 +
  152 + public int getStorageType() {
  153 + return storageType;
  154 + }
  155 +
  156 + public void setStorageType(int storageType) {
  157 + this.storageType = storageType;
  158 + }
  159 +
  160 + public long getSize() {
  161 + return size;
  162 + }
  163 +
  164 + public void setSize(long size) {
  165 + this.size = size;
  166 + }
  167 +
  168 + @Override
  169 + public String toString() {
  170 + return "JRecordItem{" +
  171 + "channelId=" + channelId +
  172 + ", startTime='" + startTime + '\'' +
  173 + ", endTime='" + endTime + '\'' +
  174 + ", warn=" + warn +
  175 + ", mediaType=" + mediaType +
  176 + ", streamType=" + streamType +
  177 + ", storageType=" + storageType +
  178 + ", size=" + size +
  179 + '}';
  180 + }
  181 + }
  182 +
  183 + @Override
  184 + public String toString() {
  185 + return "J1205{" +
  186 + "respNo=" + respNo +
  187 + ", recordList=" + recordList +
  188 + '}';
  189 + }
  190 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/request/Re.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.request;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  4 +import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  5 +import com.genersoft.iot.vmp.jt1078.session.Session;
  6 +import io.netty.buffer.ByteBuf;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +import org.springframework.util.StringUtils;
  10 +
  11 +/**
  12 + * @author QingtaiJiang
  13 + * @date 2023/4/27 18:50
  14 + * @email qingtaij@163.com
  15 + */
  16 +public abstract class Re {
  17 + private final static Logger log = LoggerFactory.getLogger(Re.class);
  18 +
  19 + protected abstract Rs decode0(ByteBuf buf, Header header, Session session);
  20 +
  21 + protected abstract Rs handler(Header header, Session session);
  22 +
  23 + public Rs decode(ByteBuf buf, Header header, Session session) {
  24 + if (session != null && !StringUtils.hasLength(session.getDevId())) {
  25 + session.register(header.getDevId(), (int) header.getVersion(), header);
  26 + }
  27 + Rs rs = decode0(buf, header, session);
  28 + Rs rsHand = handler(header, session);
  29 + if (rs == null && rsHand != null) {
  30 + rs = rsHand;
  31 + } else if (rs != null && rsHand != null) {
  32 + log.warn("decode0:{} 与 handler:{} 返回值冲突,采用decode0返回值", rs, rsHand);
  33 + }
  34 + if (rs != null) {
  35 + rs.setHeader(header);
  36 + }
  37 +
  38 + return rs;
  39 + }
  40 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J8001.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.response;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.ByteBufUtil;
  6 +import io.netty.buffer.Unpooled;
  7 +
  8 +/**
  9 + * @author QingtaiJiang
  10 + * @date 2023/4/27 18:48
  11 + * @email qingtaij@163.com
  12 + */
  13 +@MsgId(id = "8001")
  14 +public class J8001 extends Rs {
  15 + public static final Integer SUCCESS = 0;
  16 +
  17 + Integer respNo;
  18 + String respId;
  19 + Integer result;
  20 +
  21 + @Override
  22 + public ByteBuf encode() {
  23 + ByteBuf buffer = Unpooled.buffer();
  24 + buffer.writeShort(respNo);
  25 + buffer.writeBytes(ByteBufUtil.decodeHexDump(respId));
  26 + buffer.writeByte(result);
  27 +
  28 + return buffer;
  29 + }
  30 +
  31 +
  32 + public void setRespNo(Integer respNo) {
  33 + this.respNo = respNo;
  34 + }
  35 +
  36 + public void setRespId(String respId) {
  37 + this.respId = respId;
  38 + }
  39 +
  40 + public void setResult(Integer result) {
  41 + this.result = result;
  42 + }
  43 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J8100.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.response;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.Unpooled;
  6 +import io.netty.util.CharsetUtil;
  7 +
  8 +/**
  9 + * @author QingtaiJiang
  10 + * @date 2023/4/27 18:40
  11 + * @email qingtaij@163.com
  12 + */
  13 +@MsgId(id = "8100")
  14 +public class J8100 extends Rs {
  15 + public static final Integer SUCCESS = 0;
  16 +
  17 + Integer respNo;
  18 + Integer result;
  19 + String code;
  20 +
  21 + @Override
  22 + public ByteBuf encode() {
  23 + ByteBuf buffer = Unpooled.buffer();
  24 + buffer.writeShort(respNo);
  25 + buffer.writeByte(result);
  26 + buffer.writeCharSequence(code, CharsetUtil.UTF_8);
  27 + return buffer;
  28 + }
  29 +
  30 + public void setRespNo(Integer respNo) {
  31 + this.respNo = respNo;
  32 + }
  33 +
  34 + public void setResult(Integer result) {
  35 + this.result = result;
  36 + }
  37 +
  38 + public void setCode(String code) {
  39 + this.code = code;
  40 + }
  41 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9101.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.response;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.Unpooled;
  6 +import io.netty.util.CharsetUtil;
  7 +
  8 +/**
  9 + * 实时音视频传输请求
  10 + *
  11 + * @author QingtaiJiang
  12 + * @date 2023/4/27 18:25
  13 + * @email qingtaij@163.com
  14 + */
  15 +@MsgId(id = "9101")
  16 +public class J9101 extends Rs {
  17 + String ip;
  18 +
  19 + // TCP端口
  20 + Integer tcpPort;
  21 +
  22 + // UDP端口
  23 + Integer udpPort;
  24 +
  25 + // 逻辑通道号
  26 + Integer channel;
  27 +
  28 + // 数据类型
  29 + /**
  30 + * 0:音视频,1:视频,2:双向对讲,3:监听,4:中心广播,5:透传
  31 + */
  32 + Integer type;
  33 +
  34 + // 码流类型
  35 + /**
  36 + * 0:主码流,1:子码流
  37 + */
  38 + Integer rate;
  39 +
  40 + @Override
  41 + public ByteBuf encode() {
  42 + ByteBuf buffer = Unpooled.buffer();
  43 + buffer.writeByte(ip.getBytes().length);
  44 + buffer.writeCharSequence(ip, CharsetUtil.UTF_8);
  45 + buffer.writeShort(tcpPort);
  46 + buffer.writeShort(udpPort);
  47 + buffer.writeByte(channel);
  48 + buffer.writeByte(type);
  49 + buffer.writeByte(rate);
  50 + return buffer;
  51 + }
  52 +
  53 + public String getIp() {
  54 + return ip;
  55 + }
  56 +
  57 + public void setIp(String ip) {
  58 + this.ip = ip;
  59 + }
  60 +
  61 + public Integer getTcpPort() {
  62 + return tcpPort;
  63 + }
  64 +
  65 + public void setTcpPort(Integer tcpPort) {
  66 + this.tcpPort = tcpPort;
  67 + }
  68 +
  69 + public Integer getUdpPort() {
  70 + return udpPort;
  71 + }
  72 +
  73 + public void setUdpPort(Integer udpPort) {
  74 + this.udpPort = udpPort;
  75 + }
  76 +
  77 + public Integer getChannel() {
  78 + return channel;
  79 + }
  80 +
  81 + public void setChannel(Integer channel) {
  82 + this.channel = channel;
  83 + }
  84 +
  85 + public Integer getType() {
  86 + return type;
  87 + }
  88 +
  89 + public void setType(Integer type) {
  90 + this.type = type;
  91 + }
  92 +
  93 + public Integer getRate() {
  94 + return rate;
  95 + }
  96 +
  97 + public void setRate(Integer rate) {
  98 + this.rate = rate;
  99 + }
  100 +
  101 + @Override
  102 + public String toString() {
  103 + return "J9101{" +
  104 + "ip='" + ip + '\'' +
  105 + ", tcpPort=" + tcpPort +
  106 + ", udpPort=" + udpPort +
  107 + ", channel=" + channel +
  108 + ", type=" + type +
  109 + ", rate=" + rate +
  110 + '}';
  111 + }
  112 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9102.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.response;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.Unpooled;
  6 +
  7 +/**
  8 + * 音视频实时传输控制
  9 + *
  10 + * @author QingtaiJiang
  11 + * @date 2023/4/27 18:49
  12 + * @email qingtaij@163.com
  13 + */
  14 +@MsgId(id = "9102")
  15 +public class J9102 extends Rs {
  16 +
  17 + // 通道号
  18 + Integer channel;
  19 +
  20 + // 控制指令
  21 + /**
  22 + * 0:关闭音视频传输指令;
  23 + * 1:切换码流(增加暂停和继续);
  24 + * 2:暂停该通道所有流的发送;
  25 + * 3:恢复暂停前流的发送,与暂停前的流类型一致;
  26 + * 4:关闭双向对讲
  27 + */
  28 + Integer command;
  29 +
  30 + // 数据类型
  31 + /**
  32 + * 0:关闭该通道有关的音视频数据;
  33 + * 1:只关闭该通道有关的音频,保留该通道
  34 + * 有关的视频;
  35 + * 2:只关闭该通道有关的视频,保留该通道
  36 + * 有关的音频
  37 + */
  38 + Integer closeType;
  39 +
  40 + // 数据类型
  41 + /**
  42 + * 0:主码流;
  43 + * 1:子码流
  44 + */
  45 + Integer streamType;
  46 +
  47 + @Override
  48 + public ByteBuf encode() {
  49 + ByteBuf buffer = Unpooled.buffer();
  50 + buffer.writeByte(channel);
  51 + buffer.writeByte(command);
  52 + buffer.writeByte(closeType);
  53 + buffer.writeByte(streamType);
  54 + return buffer;
  55 + }
  56 +
  57 +
  58 + public Integer getChannel() {
  59 + return channel;
  60 + }
  61 +
  62 + public void setChannel(Integer channel) {
  63 + this.channel = channel;
  64 + }
  65 +
  66 + public Integer getCommand() {
  67 + return command;
  68 + }
  69 +
  70 + public void setCommand(Integer command) {
  71 + this.command = command;
  72 + }
  73 +
  74 + public Integer getCloseType() {
  75 + return closeType;
  76 + }
  77 +
  78 + public void setCloseType(Integer closeType) {
  79 + this.closeType = closeType;
  80 + }
  81 +
  82 + public Integer getStreamType() {
  83 + return streamType;
  84 + }
  85 +
  86 + public void setStreamType(Integer streamType) {
  87 + this.streamType = streamType;
  88 + }
  89 +
  90 + @Override
  91 + public String toString() {
  92 + return "J9102{" +
  93 + "channel=" + channel +
  94 + ", command=" + command +
  95 + ", closeType=" + closeType +
  96 + ", streamType=" + streamType +
  97 + '}';
  98 + }
  99 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9201.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.response;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.ByteBufUtil;
  6 +import io.netty.buffer.Unpooled;
  7 +import io.netty.util.CharsetUtil;
  8 +
  9 +/**
  10 + * 回放请求
  11 + *
  12 + * @author QingtaiJiang
  13 + * @date 2023/4/28 10:37
  14 + * @email qingtaij@163.com
  15 + */
  16 +@MsgId(id = "9201")
  17 +public class J9201 extends Rs {
  18 + // 服务器IP地址
  19 + private String ip;
  20 +
  21 + // 实时视频服务器TCP端口号
  22 + private int tcpPort;
  23 +
  24 + // 实时视频服务器UDP端口号
  25 + private int udpPort;
  26 +
  27 + // 逻辑通道号
  28 + private int channel;
  29 +
  30 + // 音视频资源类型:0.音视频 1.音频 2.视频 3.视频或音视频
  31 + private int type;
  32 +
  33 + // 码流类型:0.所有码流 1.主码流 2.子码流(如果此通道只传输音频,此字段置0)
  34 + private int rate;
  35 +
  36 + // 存储器类型:0.所有存储器 1.主存储器 2.灾备存储器"
  37 + private int storageType;
  38 +
  39 + // 回放方式:0.正常回放 1.快进回放 2.关键帧快退回放 3.关键帧播放 4.单帧上传
  40 + private int playbackType;
  41 +
  42 + // 快进或快退倍数:0.无效 1.1倍 2.2倍 3.4倍 4.8倍 5.16倍 (回放控制为1和2时,此字段内容有效,否则置0)
  43 + private int playbackSpeed;
  44 +
  45 + // 开始时间YYMMDDHHMMSS,回放方式为4时,该字段表示单帧上传时间
  46 + private String startTime;
  47 +
  48 + // 结束时间YYMMDDHHMMSS,回放方式为4时,该字段无效,为0表示一直回放
  49 + private String endTime;
  50 +
  51 + @Override
  52 + public ByteBuf encode() {
  53 + ByteBuf buffer = Unpooled.buffer();
  54 + buffer.writeByte(ip.getBytes().length);
  55 + buffer.writeCharSequence(ip, CharsetUtil.UTF_8);
  56 + buffer.writeShort(tcpPort);
  57 + buffer.writeShort(udpPort);
  58 + buffer.writeByte(channel);
  59 + buffer.writeByte(type);
  60 + buffer.writeByte(rate);
  61 + buffer.writeByte(storageType);
  62 + buffer.writeByte(playbackType);
  63 + buffer.writeByte(playbackSpeed);
  64 + buffer.writeBytes(ByteBufUtil.decodeHexDump(startTime));
  65 + buffer.writeBytes(ByteBufUtil.decodeHexDump(endTime));
  66 + return buffer;
  67 + }
  68 +
  69 + public String getIp() {
  70 + return ip;
  71 + }
  72 +
  73 + public void setIp(String ip) {
  74 + this.ip = ip;
  75 + }
  76 +
  77 + public int getTcpPort() {
  78 + return tcpPort;
  79 + }
  80 +
  81 + public void setTcpPort(int tcpPort) {
  82 + this.tcpPort = tcpPort;
  83 + }
  84 +
  85 + public int getUdpPort() {
  86 + return udpPort;
  87 + }
  88 +
  89 + public void setUdpPort(int udpPort) {
  90 + this.udpPort = udpPort;
  91 + }
  92 +
  93 + public int getChannel() {
  94 + return channel;
  95 + }
  96 +
  97 + public void setChannel(int channel) {
  98 + this.channel = channel;
  99 + }
  100 +
  101 + public int getType() {
  102 + return type;
  103 + }
  104 +
  105 + public void setType(int type) {
  106 + this.type = type;
  107 + }
  108 +
  109 + public int getRate() {
  110 + return rate;
  111 + }
  112 +
  113 + public void setRate(int rate) {
  114 + this.rate = rate;
  115 + }
  116 +
  117 + public int getStorageType() {
  118 + return storageType;
  119 + }
  120 +
  121 + public void setStorageType(int storageType) {
  122 + this.storageType = storageType;
  123 + }
  124 +
  125 + public int getPlaybackType() {
  126 + return playbackType;
  127 + }
  128 +
  129 + public void setPlaybackType(int playbackType) {
  130 + this.playbackType = playbackType;
  131 + }
  132 +
  133 + public int getPlaybackSpeed() {
  134 + return playbackSpeed;
  135 + }
  136 +
  137 + public void setPlaybackSpeed(int playbackSpeed) {
  138 + this.playbackSpeed = playbackSpeed;
  139 + }
  140 +
  141 + public String getStartTime() {
  142 + return startTime;
  143 + }
  144 +
  145 + public void setStartTime(String startTime) {
  146 + this.startTime = startTime;
  147 + }
  148 +
  149 + public String getEndTime() {
  150 + return endTime;
  151 + }
  152 +
  153 + public void setEndTime(String endTime) {
  154 + this.endTime = endTime;
  155 + }
  156 +
  157 + @Override
  158 + public String toString() {
  159 + return "J9201{" +
  160 + "ip='" + ip + '\'' +
  161 + ", tcpPort=" + tcpPort +
  162 + ", udpPort=" + udpPort +
  163 + ", channel=" + channel +
  164 + ", type=" + type +
  165 + ", rate=" + rate +
  166 + ", storageType=" + storageType +
  167 + ", playbackType=" + playbackType +
  168 + ", playbackSpeed=" + playbackSpeed +
  169 + ", startTime='" + startTime + '\'' +
  170 + ", endTime='" + endTime + '\'' +
  171 + '}';
  172 + }
  173 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9202.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.response;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.ByteBufUtil;
  6 +import io.netty.buffer.Unpooled;
  7 +
  8 +/**
  9 + * 平台下发远程录像回放控制
  10 + *
  11 + * @author QingtaiJiang
  12 + * @date 2023/4/28 10:37
  13 + * @email qingtaij@163.com
  14 + */
  15 +@MsgId(id = "9202")
  16 +public class J9202 extends Rs {
  17 + // 逻辑通道号
  18 + private int channel;
  19 +
  20 + // 回放控制:0.开始回放 1.暂停回放 2.结束回放 3.快进回放 4.关键帧快退回放 5.拖动回放 6.关键帧播放
  21 + private int playbackType;
  22 +
  23 + // 快进或快退倍数:0.无效 1.1倍 2.2倍 3.4倍 4.8倍 5.16倍 (回放控制为3和4时,此字段内容有效,否则置0)
  24 + private int playbackSpeed;
  25 +
  26 + // 拖动回放位置(YYMMDDHHMMSS,回放控制为5时,此字段有效)
  27 + private String playbackTime;
  28 +
  29 + @Override
  30 + public ByteBuf encode() {
  31 + ByteBuf buffer = Unpooled.buffer();
  32 + buffer.writeByte(channel);
  33 + buffer.writeByte(playbackType);
  34 + buffer.writeByte(playbackSpeed);
  35 + buffer.writeBytes(ByteBufUtil.decodeHexDump(playbackTime));
  36 + return buffer;
  37 + }
  38 +
  39 + public int getChannel() {
  40 + return channel;
  41 + }
  42 +
  43 + public void setChannel(int channel) {
  44 + this.channel = channel;
  45 + }
  46 +
  47 + public int getPlaybackType() {
  48 + return playbackType;
  49 + }
  50 +
  51 + public void setPlaybackType(int playbackType) {
  52 + this.playbackType = playbackType;
  53 + }
  54 +
  55 + public int getPlaybackSpeed() {
  56 + return playbackSpeed;
  57 + }
  58 +
  59 + public void setPlaybackSpeed(int playbackSpeed) {
  60 + this.playbackSpeed = playbackSpeed;
  61 + }
  62 +
  63 + public String getPlaybackTime() {
  64 + return playbackTime;
  65 + }
  66 +
  67 + public void setPlaybackTime(String playbackTime) {
  68 + this.playbackTime = playbackTime;
  69 + }
  70 +
  71 + @Override
  72 + public String toString() {
  73 + return "J9202{" +
  74 + "channel=" + channel +
  75 + ", playbackType=" + playbackType +
  76 + ", playbackSpeed=" + playbackSpeed +
  77 + ", playbackTime='" + playbackTime + '\'' +
  78 + '}';
  79 + }
  80 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/J9205.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.response;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
  4 +import io.netty.buffer.ByteBuf;
  5 +import io.netty.buffer.ByteBufUtil;
  6 +import io.netty.buffer.Unpooled;
  7 +
  8 +/**
  9 + * 查询资源列表
  10 + *
  11 + * @author QingtaiJiang
  12 + * @date 2023/4/28 10:36
  13 + * @email qingtaij@163.com
  14 + */
  15 +@MsgId(id = "9205")
  16 +public class J9205 extends Rs {
  17 + // 逻辑通道号
  18 + private int channelId;
  19 +
  20 + // 开始时间YYMMDDHHMMSS,全0表示无起始时间
  21 + private String startTime;
  22 +
  23 + // 结束时间YYMMDDHHMMSS,全0表示无终止时间
  24 + private String endTime;
  25 +
  26 + // 报警标志
  27 + private final int warnType = 0;
  28 +
  29 + // 音视频资源类型:0.音视频 1.音频 2.视频 3.视频或音视频
  30 + private int mediaType;
  31 +
  32 + // 码流类型:0.所有码流 1.主码流 2.子码流
  33 + private int streamType = 0;
  34 +
  35 + // 存储器类型:0.所有存储器 1.主存储器 2.灾备存储器
  36 + private int storageType = 0;
  37 +
  38 + @Override
  39 + public ByteBuf encode() {
  40 + ByteBuf buffer = Unpooled.buffer();
  41 +
  42 + buffer.writeByte(channelId);
  43 + buffer.writeBytes(ByteBufUtil.decodeHexDump(startTime));
  44 + buffer.writeBytes(ByteBufUtil.decodeHexDump(endTime));
  45 + buffer.writeLong(warnType);
  46 + buffer.writeByte(mediaType);
  47 + buffer.writeByte(streamType);
  48 + buffer.writeByte(storageType);
  49 +
  50 + return buffer;
  51 + }
  52 +
  53 +
  54 + public void setChannelId(int channelId) {
  55 + this.channelId = channelId;
  56 + }
  57 +
  58 + public void setStartTime(String startTime) {
  59 + this.startTime = startTime;
  60 + }
  61 +
  62 + public void setEndTime(String endTime) {
  63 + this.endTime = endTime;
  64 + }
  65 +
  66 + public void setMediaType(int mediaType) {
  67 + this.mediaType = mediaType;
  68 + }
  69 +
  70 + public void setStreamType(int streamType) {
  71 + this.streamType = streamType;
  72 + }
  73 +
  74 + public void setStorageType(int storageType) {
  75 + this.storageType = storageType;
  76 + }
  77 +
  78 + public int getWarnType() {
  79 + return warnType;
  80 + }
  81 +
  82 + @Override
  83 + public String toString() {
  84 + return "J9205{" +
  85 + "channelId=" + channelId +
  86 + ", startTime='" + startTime + '\'' +
  87 + ", endTime='" + endTime + '\'' +
  88 + ", warnType=" + warnType +
  89 + ", mediaType=" + mediaType +
  90 + ", streamType=" + streamType +
  91 + ", storageType=" + storageType +
  92 + '}';
  93 + }
  94 +}
src/main/java/com/genersoft/iot/vmp/jt1078/proc/response/Rs.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.proc.response;
  2 +
  3 +
  4 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  5 +import io.netty.buffer.ByteBuf;
  6 +
  7 +
  8 +/**
  9 + * @author QingtaiJiang
  10 + * @date 2021/8/30 18:54
  11 + * @email qingtaij@163.com
  12 + */
  13 +
  14 +public abstract class Rs {
  15 + private Header header;
  16 +
  17 + public abstract ByteBuf encode();
  18 +
  19 +
  20 + public Header getHeader() {
  21 + return header;
  22 + }
  23 +
  24 + public void setHeader(Header header) {
  25 + this.header = header;
  26 + }
  27 +}
src/main/java/com/genersoft/iot/vmp/jt1078/session/Session.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.session;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.proc.Header;
  4 +import io.netty.channel.Channel;
  5 +import io.netty.util.AttributeKey;
  6 +import org.slf4j.Logger;
  7 +import org.slf4j.LoggerFactory;
  8 +
  9 +import java.util.concurrent.atomic.AtomicInteger;
  10 +
  11 +/**
  12 + * @author QingtaiJiang
  13 + * @date 2023/4/27 18:54
  14 + * @email qingtaij@163.com
  15 + */
  16 +public class Session {
  17 + private final static Logger log = LoggerFactory.getLogger(Session.class);
  18 +
  19 + public static final AttributeKey<Session> KEY = AttributeKey.newInstance(Session.class.getName());
  20 +
  21 + // Netty的channel
  22 + protected final Channel channel;
  23 +
  24 + // 原子类的自增ID
  25 + private final AtomicInteger serialNo = new AtomicInteger(0);
  26 +
  27 + // 是否注册成功
  28 + private boolean registered = false;
  29 +
  30 + // 设备ID
  31 + private String devId;
  32 +
  33 + // 创建时间
  34 + private final long creationTime;
  35 +
  36 + // 协议版本号
  37 + private Integer protocolVersion;
  38 +
  39 + private Header header;
  40 +
  41 + protected Session(Channel channel) {
  42 + this.channel = channel;
  43 + this.creationTime = System.currentTimeMillis();
  44 + }
  45 +
  46 + public void writeObject(Object message) {
  47 + log.info("<<<<<<<<<< cmd{},{}", this, message);
  48 + channel.writeAndFlush(message);
  49 + }
  50 +
  51 + /**
  52 + * 获得下一个流水号
  53 + *
  54 + * @return 流水号
  55 + */
  56 + public int nextSerialNo() {
  57 + int current;
  58 + int next;
  59 + do {
  60 + current = serialNo.get();
  61 + next = current > 0xffff ? 0 : current;
  62 + } while (!serialNo.compareAndSet(current, next + 1));
  63 + return next;
  64 + }
  65 +
  66 + /**
  67 + * 注册session
  68 + *
  69 + * @param devId 设备ID
  70 + */
  71 + public void register(String devId, Integer version, Header header) {
  72 + this.devId = devId;
  73 + this.registered = true;
  74 + this.protocolVersion = version;
  75 + this.header = header;
  76 + SessionManager.INSTANCE.put(devId, this);
  77 + }
  78 +
  79 + /**
  80 + * 获取设备号
  81 + *
  82 + * @return 设备号
  83 + */
  84 + public String getDevId() {
  85 + return devId;
  86 + }
  87 +
  88 +
  89 + public boolean isRegistered() {
  90 + return registered;
  91 + }
  92 +
  93 + public long getCreationTime() {
  94 + return creationTime;
  95 + }
  96 +
  97 + public Integer getProtocolVersion() {
  98 + return protocolVersion;
  99 + }
  100 +
  101 + public Header getHeader() {
  102 + return header;
  103 + }
  104 +
  105 + @Override
  106 + public String toString() {
  107 + return "[" +
  108 + "devId=" + devId +
  109 + ", reg=" + registered +
  110 + ", version=" + protocolVersion +
  111 + ",ip=" + channel.remoteAddress() +
  112 + ']';
  113 + }
  114 +}
src/main/java/com/genersoft/iot/vmp/jt1078/session/SessionManager.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.session;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.proc.entity.Cmd;
  4 +import io.netty.channel.Channel;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
  7 +
  8 +import java.util.Map;
  9 +import java.util.concurrent.ConcurrentHashMap;
  10 +import java.util.concurrent.SynchronousQueue;
  11 +import java.util.concurrent.TimeUnit;
  12 +
  13 +
  14 +/**
  15 + * @author QingtaiJiang
  16 + * @date 2023/4/27 19:54
  17 + * @email qingtaij@163.com
  18 + */
  19 +public enum SessionManager {
  20 + INSTANCE;
  21 + private final static Logger log = LoggerFactory.getLogger(SessionManager.class);
  22 +
  23 + // 用与消息的缓存
  24 + private final Map<String, SynchronousQueue<String>> topicSubscribers = new ConcurrentHashMap<>();
  25 +
  26 + // session的缓存
  27 + private final Map<Object, Session> sessionMap;
  28 +
  29 + SessionManager() {
  30 + this.sessionMap = new ConcurrentHashMap<>();
  31 + }
  32 +
  33 + /**
  34 + * 创建新的Session
  35 + *
  36 + * @param channel netty通道
  37 + * @return 创建的session对象
  38 + */
  39 + public Session newSession(Channel channel) {
  40 + return new Session(channel);
  41 + }
  42 +
  43 +
  44 + /**
  45 + * 获取指定设备的Session
  46 + *
  47 + * @param clientId 设备Id
  48 + * @return Session
  49 + */
  50 + public Session get(Object clientId) {
  51 + return sessionMap.get(clientId);
  52 + }
  53 +
  54 + /**
  55 + * 放入新设备连接的session
  56 + *
  57 + * @param clientId 设备ID
  58 + * @param newSession session
  59 + */
  60 + protected void put(Object clientId, Session newSession) {
  61 + sessionMap.put(clientId, newSession);
  62 + }
  63 +
  64 +
  65 + /**
  66 + * 发送同步消息,接收响应
  67 + * 默认超时时间6秒
  68 + */
  69 + public String request(Cmd cmd) {
  70 + // 默认6秒
  71 + int timeOut = 6000;
  72 + return request(cmd, timeOut);
  73 + }
  74 +
  75 + public String request(Cmd cmd, Integer timeOut) {
  76 + Session session = this.get(cmd.getDevId());
  77 + if (session == null) {
  78 + log.error("DevId: {} not online!", cmd.getDevId());
  79 + return null;
  80 + }
  81 + String requestKey = requestKey(cmd.getDevId(), cmd.getRespId(), cmd.getPackageNo());
  82 + SynchronousQueue<String> subscribe = subscribe(requestKey);
  83 + if (subscribe == null) {
  84 + log.error("DevId: {} key:{} send repaid", cmd.getDevId(), requestKey);
  85 + return null;
  86 + }
  87 + session.writeObject(cmd);
  88 + try {
  89 + return subscribe.poll(timeOut, TimeUnit.SECONDS);
  90 + } catch (InterruptedException e) {
  91 + log.warn("<<<<<<<<<< timeout" + session, e);
  92 + } finally {
  93 + this.unsubscribe(requestKey);
  94 + }
  95 + return null;
  96 + }
  97 +
  98 + public Boolean response(String devId, String respId, Long responseNo, String data) {
  99 + String requestKey = requestKey(devId, respId, responseNo);
  100 + SynchronousQueue<String> queue = topicSubscribers.get(requestKey);
  101 + if (queue != null) {
  102 + try {
  103 + return queue.offer(data, 2, TimeUnit.SECONDS);
  104 + } catch (InterruptedException e) {
  105 + log.error("{}", e.getMessage(), e);
  106 + }
  107 + }
  108 + log.warn("Not find response,key:{} data:{} ", requestKey, data);
  109 + return false;
  110 + }
  111 +
  112 + private void unsubscribe(String key) {
  113 + topicSubscribers.remove(key);
  114 + }
  115 +
  116 + private SynchronousQueue<String> subscribe(String key) {
  117 + SynchronousQueue<String> queue = null;
  118 + if (!topicSubscribers.containsKey(key))
  119 + topicSubscribers.put(key, queue = new SynchronousQueue<String>());
  120 + return queue;
  121 + }
  122 +
  123 + private String requestKey(String devId, String respId, Long requestNo) {
  124 + return String.join("_", devId.replaceFirst("^0*", ""), respId, requestNo.toString());
  125 + }
  126 +
  127 +}
src/main/java/com/genersoft/iot/vmp/jt1078/util/Bin.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.util;
  2 +
  3 +/**
  4 + * 32位整型的二进制读写
  5 + */
  6 +public class Bin {
  7 +
  8 + private static final int[] bits = new int[32];
  9 +
  10 + static {
  11 + bits[0] = 1;
  12 + for (int i = 1; i < bits.length; i++) {
  13 + bits[i] = bits[i - 1] << 1;
  14 + }
  15 + }
  16 +
  17 + /**
  18 + * 读取n的第i位
  19 + *
  20 + * @param n int32
  21 + * @param i 取值范围0-31
  22 + */
  23 + public static boolean get(int n, int i) {
  24 + return (n & bits[i]) == bits[i];
  25 + }
  26 +
  27 + /**
  28 + * 不足位数从左边加0
  29 + */
  30 + public static String strHexPaddingLeft(String data, int length) {
  31 + int dataLength = data.length();
  32 + if (dataLength < length) {
  33 + StringBuilder dataBuilder = new StringBuilder(data);
  34 + for (int i = dataLength; i < length; i++) {
  35 + dataBuilder.insert(0, "0");
  36 + }
  37 + data = dataBuilder.toString();
  38 + }
  39 + return data;
  40 + }
  41 +}
src/main/java/com/genersoft/iot/vmp/jt1078/util/ClassUtil.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078.util;
  2 +
  3 +import org.slf4j.Logger;
  4 +import org.slf4j.LoggerFactory;
  5 +import org.springframework.core.io.Resource;
  6 +import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
  7 +import org.springframework.core.io.support.ResourcePatternResolver;
  8 +
  9 +import java.lang.annotation.Annotation;
  10 +import java.util.LinkedList;
  11 +import java.util.List;
  12 +
  13 +public class ClassUtil {
  14 +
  15 + private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class);
  16 +
  17 +
  18 + public static Object getBean(Class<?> clazz) {
  19 + if (clazz != null) {
  20 + try {
  21 + return clazz.getDeclaredConstructor().newInstance();
  22 + } catch (Exception ex) {
  23 + logger.error("ClassUtil:找不到指定的类", ex);
  24 + }
  25 + }
  26 + return null;
  27 + }
  28 +
  29 +
  30 + public static Object getBean(String className) {
  31 + Class<?> clazz = null;
  32 + try {
  33 + clazz = Class.forName(className);
  34 + } catch (Exception ex) {
  35 + logger.error("ClassUtil:找不到指定的类");
  36 + }
  37 + if (clazz != null) {
  38 + try {
  39 + //获取声明的构造器--》创建实例
  40 + return clazz.getDeclaredConstructor().newInstance();
  41 + } catch (Exception ex) {
  42 + logger.error("ClassUtil:找不到指定的类", ex);
  43 + }
  44 + }
  45 + return null;
  46 + }
  47 +
  48 +
  49 + /**
  50 + * 获取包下所有带注解的class
  51 + *
  52 + * @param packageName 包名
  53 + * @param annotationClass 注解类型
  54 + * @return list
  55 + */
  56 + public static List<Class<?>> getClassList(String packageName, Class<? extends Annotation> annotationClass) {
  57 + List<Class<?>> classList = getClassList(packageName);
  58 + classList.removeIf(next -> !next.isAnnotationPresent(annotationClass));
  59 + return classList;
  60 + }
  61 +
  62 + public static List<Class<?>> getClassList(String... packageName) {
  63 + List<Class<?>> classList = new LinkedList<>();
  64 + for (String s : packageName) {
  65 + List<Class<?>> c = getClassList(s);
  66 + classList.addAll(c);
  67 + }
  68 + return classList;
  69 + }
  70 +
  71 + public static List<Class<?>> getClassList(String packageName) {
  72 + List<Class<?>> classList = new LinkedList<>();
  73 + try {
  74 + ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
  75 + Resource[] resources = resourcePatternResolver.getResources(packageName.replace(".", "/") + "/**/*.class");
  76 + for (Resource resource : resources) {
  77 + String url = resource.getURL().toString();
  78 +
  79 + String[] split = url.split(packageName.replace(".", "/"));
  80 + String s = split[split.length - 1];
  81 + String className = s.replace("/", ".");
  82 + className = className.substring(0, className.lastIndexOf("."));
  83 + doAddClass(classList, packageName + className);
  84 + }
  85 +
  86 + } catch (Exception e) {
  87 + throw new RuntimeException(e);
  88 + }
  89 + return classList;
  90 + }
  91 +
  92 + private static void doAddClass(List<Class<?>> classList, String className) {
  93 + Class<?> cls = loadClass(className, false);
  94 + classList.add(cls);
  95 + }
  96 +
  97 + public static Class<?> loadClass(String className, boolean isInitialized) {
  98 + Class<?> cls;
  99 + try {
  100 + cls = Class.forName(className, isInitialized, getClassLoader());
  101 + } catch (ClassNotFoundException e) {
  102 + throw new RuntimeException(e);
  103 + }
  104 + return cls;
  105 + }
  106 +
  107 +
  108 + public static ClassLoader getClassLoader() {
  109 + return Thread.currentThread().getContextClassLoader();
  110 + }
  111 +
  112 +}
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -2,12 +2,16 @@ package com.genersoft.iot.vmp.media.zlm; @@ -2,12 +2,16 @@ package com.genersoft.iot.vmp.media.zlm;
2 2
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.alibaba.fastjson2.JSONObject; 4 import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.InviteInfo;
  6 +import com.genersoft.iot.vmp.common.InviteSessionType;
5 import com.genersoft.iot.vmp.common.StreamInfo; 7 import com.genersoft.iot.vmp.common.StreamInfo;
6 import com.genersoft.iot.vmp.conf.UserSetting; 8 import com.genersoft.iot.vmp.conf.UserSetting;
7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 9 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
8 import com.genersoft.iot.vmp.gb28181.bean.*; 10 import com.genersoft.iot.vmp.gb28181.bean.*;
9 import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 11 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
10 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; 12 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
  13 +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
  14 +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
11 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 15 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
12 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 16 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
13 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 17 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
@@ -21,10 +25,8 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.*; @@ -21,10 +25,8 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
21 import com.genersoft.iot.vmp.service.*; 25 import com.genersoft.iot.vmp.service.*;
22 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 26 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
23 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 27 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
24 -import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx;  
25 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 28 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
26 import com.genersoft.iot.vmp.vmanager.bean.StreamContent; 29 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
27 -import com.genersoft.iot.vmp.vmanager.bean.WVPResult;  
28 import org.slf4j.Logger; 30 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory; 31 import org.slf4j.LoggerFactory;
30 import org.springframework.beans.factory.annotation.Autowired; 32 import org.springframework.beans.factory.annotation.Autowired;
@@ -57,14 +59,14 @@ public class ZLMHttpHookListener { @@ -57,14 +59,14 @@ public class ZLMHttpHookListener {
57 @Autowired 59 @Autowired
58 private SIPCommander cmder; 60 private SIPCommander cmder;
59 61
60 - @Autowired  
61 - private ISIPCommanderForPlatform commanderFroPlatform; 62 + @Autowired
  63 + private ISIPCommanderForPlatform commanderFroPlatform;
62 64
63 - @Autowired  
64 - private AudioBroadcastManager audioBroadcastManager; 65 + @Autowired
  66 + private AudioBroadcastManager audioBroadcastManager;
65 67
66 - @Autowired  
67 - private ZLMRTPServerFactory zlmrtpServerFactory; 68 + @Autowired
  69 + private ZLMRTPServerFactory zlmrtpServerFactory;
68 70
69 @Autowired 71 @Autowired
70 private IPlayService playService; 72 private IPlayService playService;
@@ -76,6 +78,9 @@ public class ZLMHttpHookListener { @@ -76,6 +78,9 @@ public class ZLMHttpHookListener {
76 private IRedisCatchStorage redisCatchStorage; 78 private IRedisCatchStorage redisCatchStorage;
77 79
78 @Autowired 80 @Autowired
  81 + private IInviteStreamService inviteStreamService;
  82 +
  83 + @Autowired
79 private IDeviceService deviceService; 84 private IDeviceService deviceService;
80 85
81 @Autowired 86 @Autowired
@@ -111,6 +116,9 @@ public class ZLMHttpHookListener { @@ -111,6 +116,9 @@ public class ZLMHttpHookListener {
111 @Autowired 116 @Autowired
112 private AssistRESTfulUtils assistRESTfulUtils; 117 private AssistRESTfulUtils assistRESTfulUtils;
113 118
  119 + @Autowired
  120 + private SSRCFactory ssrcFactory;
  121 +
114 @Qualifier("taskExecutor") 122 @Qualifier("taskExecutor")
115 @Autowired 123 @Autowired
116 private ThreadPoolTaskExecutor taskExecutor; 124 private ThreadPoolTaskExecutor taskExecutor;
@@ -255,13 +263,13 @@ public class ZLMHttpHookListener { @@ -255,13 +263,13 @@ public class ZLMHttpHookListener {
255 result.setEnable_audio(deviceChannel.isHasAudio()); 263 result.setEnable_audio(deviceChannel.isHasAudio());
256 } 264 }
257 // 如果是录像下载就设置视频间隔十秒 265 // 如果是录像下载就设置视频间隔十秒
258 - if (ssrcTransactionForAll.get(0).getType() == VideoStreamSessionManager.SessionType.download) { 266 + if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) {
259 result.setMp4_max_second(10); 267 result.setMp4_max_second(10);
260 result.setEnable_audio(true); 268 result.setEnable_audio(true);
261 result.setEnable_mp4(true); 269 result.setEnable_mp4(true);
262 } 270 }
263 // 如果是talk对讲,则默认获取声音 271 // 如果是talk对讲,则默认获取声音
264 - if (ssrcTransactionForAll.get(0).getType() == VideoStreamSessionManager.SessionType.talk) { 272 + if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.TALK) {
265 result.setEnable_audio(true); 273 result.setEnable_audio(true);
266 } 274 }
267 275
@@ -269,7 +277,7 @@ public class ZLMHttpHookListener { @@ -269,7 +277,7 @@ public class ZLMHttpHookListener {
269 if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { 277 if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) {
270 logger.info("推流时发现尚未设置录像路径,从assist服务中读取"); 278 logger.info("推流时发现尚未设置录像路径,从assist服务中读取");
271 JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null); 279 JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null);
272 - if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) { 280 + if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0) {
273 JSONObject dataJson = info.getJSONObject("data"); 281 JSONObject dataJson = info.getJSONObject("data");
274 if (dataJson != null) { 282 if (dataJson != null) {
275 String recordPath = dataJson.getString("record"); 283 String recordPath = dataJson.getString("record");
@@ -301,29 +309,30 @@ public class ZLMHttpHookListener { @@ -301,29 +309,30 @@ public class ZLMHttpHookListener {
301 logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); 309 logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
302 } 310 }
303 311
304 - JSONObject ret = new JSONObject();  
305 - ret.put("code", 0);  
306 - ret.put("msg", "success"); 312 + JSONObject ret = new JSONObject();
  313 + ret.put("code", 0);
  314 + ret.put("msg", "success");
307 MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId()); 315 MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
308 JSONObject json = (JSONObject) JSON.toJSON(param); 316 JSONObject json = (JSONObject) JSON.toJSON(param);
309 taskExecutor.execute(() -> { 317 taskExecutor.execute(() -> {
310 ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json); 318 ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
  319 + if (mediaInfo == null) {
  320 + logger.info("[ZLM HOOK] 流变化未找到ZLM, {}", param.getMediaServerId());
  321 + return;
  322 + }
311 if (subscribe != null) { 323 if (subscribe != null) {
312 -  
313 - if (mediaInfo != null) {  
314 - subscribe.response(mediaInfo, json);  
315 - } 324 + subscribe.response(mediaInfo, json);
316 } 325 }
317 326
318 List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); 327 List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
319 // TODO 重构此处逻辑 328 // TODO 重构此处逻辑
320 - 329 + boolean isPush = false;
321 if (param.isRegist()) { 330 if (param.isRegist()) {
322 // 处理流注册的鉴权信息 331 // 处理流注册的鉴权信息
323 if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() 332 if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
324 || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() 333 || param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
325 || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { 334 || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
326 - 335 + isPush = true;
327 StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); 336 StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
328 if (streamAuthorityInfo == null) { 337 if (streamAuthorityInfo == null) {
329 streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); 338 streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
@@ -337,123 +346,122 @@ public class ZLMHttpHookListener { @@ -337,123 +346,122 @@ public class ZLMHttpHookListener {
337 redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); 346 redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream());
338 } 347 }
339 348
340 - if ("rtsp".equals(param.getSchema())){  
341 - logger.info("流变化:注册->{}, app->{}, stream->{}", param.isRegist(), param.getApp(), param.getStream());  
342 - if (param.isRegist()) {  
343 - mediaServerService.addCount(param.getMediaServerId());  
344 - }else {  
345 - mediaServerService.removeCount(param.getMediaServerId());  
346 - }  
347 - if (param.getOriginType() == OriginType.PULL.ordinal()  
348 - || param.getOriginType() == OriginType.FFMPEG_PULL.ordinal()) {  
349 - // 设置拉流代理上线/离线  
350 - streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream());  
351 - }  
352 - if ("rtp".equals(param.getApp()) && !param.isRegist() ) {  
353 - StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(param.getStream());  
354 - if (streamInfo!=null){  
355 - redisCatchStorage.stopPlay(streamInfo);  
356 - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());  
357 - }else{  
358 - streamInfo = redisCatchStorage.queryPlayback(null, null, param.getStream(), null);  
359 - if (streamInfo != null) {  
360 - redisCatchStorage.stopPlayback(streamInfo.getDeviceID(), streamInfo.getChannelId(),  
361 - streamInfo.getStream(), null);  
362 - }  
363 - }  
364 - }else if ("broadcast".equals(param.getApp())){  
365 - // 语音对讲推流 stream需要满足格式deviceId_channelId  
366 - if (param.getStream().indexOf("_") > 0) {  
367 - String[] streamArray = param.getStream().split("_");  
368 - if (streamArray.length == 2) {  
369 - String deviceId = streamArray[0];  
370 - String channelId = streamArray[1];  
371 - Device device = deviceService.getDevice(deviceId);  
372 - if (device != null) {  
373 - if (param.isRegist()) {  
374 - if (audioBroadcastManager.exit(deviceId, channelId)) { 349 + if ("rtsp".equals(param.getSchema())) {
  350 + logger.info("流变化:注册->{}, app->{}, stream->{}", param.isRegist(), param.getApp(), param.getStream());
  351 + if (param.isRegist()) {
  352 + mediaServerService.addCount(param.getMediaServerId());
  353 + } else {
  354 + mediaServerService.removeCount(param.getMediaServerId());
  355 + }
  356 +
  357 + int updateStatusResult = streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream());
  358 + if (updateStatusResult > 0) {
  359 +
  360 + }
  361 +
  362 + if ("rtp".equals(param.getApp()) && !param.isRegist()) {
  363 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
  364 + if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) {
  365 + inviteStreamService.removeInviteInfo(inviteInfo);
  366 + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
  367 + }
  368 + } else if ("broadcast".equals(param.getApp())) {
  369 + // 语音对讲推流 stream需要满足格式deviceId_channelId
  370 + if (param.getStream().indexOf("_") > 0) {
  371 + String[] streamArray = param.getStream().split("_");
  372 + if (streamArray.length == 2) {
  373 + String deviceId = streamArray[0];
  374 + String channelId = streamArray[1];
  375 + Device device = deviceService.getDevice(deviceId);
  376 + if (device != null) {
  377 + if (param.isRegist()) {
  378 + if (audioBroadcastManager.exit(deviceId, channelId)) {
  379 + playService.stopAudioBroadcast(deviceId, channelId);
  380 + }
  381 + // 开启语音对讲通道
  382 + try {
  383 + playService.audioBroadcastCmd(device, channelId, mediaInfo, param.getApp(), param.getStream(), 60, false, (msg) -> {
  384 + logger.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId);
  385 + });
  386 + } catch (InvalidArgumentException | ParseException | SipException e) {
  387 + logger.error("[命令发送失败] 语音对讲: {}", e.getMessage());
  388 + }
  389 + } else {
  390 + // 流注销
375 playService.stopAudioBroadcast(deviceId, channelId); 391 playService.stopAudioBroadcast(deviceId, channelId);
376 } 392 }
377 - // 开启语音对讲通道  
378 - try {  
379 - playService.audioBroadcastCmd(device, channelId, mediaInfo, param.getApp(), param.getStream(), 60, false, (msg)->{  
380 - logger.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId);  
381 - });  
382 - } catch (InvalidArgumentException | ParseException | SipException e) {  
383 - logger.error("[命令发送失败] 语音对讲: {}", e.getMessage());  
384 - }  
385 - }else {  
386 - // 流注销  
387 - playService.stopAudioBroadcast(deviceId, channelId); 393 + } else {
  394 + logger.info("[语音对讲] 未找到设备:{}", deviceId);
388 } 395 }
389 - } else{  
390 - logger.info("[语音对讲] 未找到设备:{}", deviceId);  
391 } 396 }
392 } 397 }
393 - }  
394 - }else if ("talk".equals(param.getApp())){  
395 - // 语音对讲推流 stream需要满足格式deviceId_channelId  
396 - if (param.getStream().indexOf("_") > 0) {  
397 - String[] streamArray = param.getStream().split("_");  
398 - if (streamArray.length == 2) {  
399 - String deviceId = streamArray[0];  
400 - String channelId = streamArray[1];  
401 - Device device = deviceService.getDevice(deviceId);  
402 - if (device != null) {  
403 - if (param.isRegist()) {  
404 - if (audioBroadcastManager.exit(deviceId, channelId)) {  
405 - playService.stopAudioBroadcast(deviceId, channelId); 398 + } else if ("talk".equals(param.getApp())) {
  399 + // 语音对讲推流 stream需要满足格式deviceId_channelId
  400 + if (param.getStream().indexOf("_") > 0) {
  401 + String[] streamArray = param.getStream().split("_");
  402 + if (streamArray.length == 2) {
  403 + String deviceId = streamArray[0];
  404 + String channelId = streamArray[1];
  405 + Device device = deviceService.getDevice(deviceId);
  406 + if (device != null) {
  407 + if (param.isRegist()) {
  408 + if (audioBroadcastManager.exit(deviceId, channelId)) {
  409 + playService.stopAudioBroadcast(deviceId, channelId);
  410 + }
  411 + // 开启语音对讲通道
  412 + playService.talkCmd(device, channelId, mediaInfo, param.getStream(), (msg) -> {
  413 + logger.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId);
  414 + });
  415 + } else {
  416 + // 流注销
  417 + playService.stopTalk(device, channelId, param.isRegist());
406 } 418 }
407 - // 开启语音对讲通道  
408 - playService.talkCmd(device, channelId, mediaInfo, param.getStream(), (msg)->{  
409 - logger.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId);  
410 - });  
411 - }else {  
412 - // 流注销  
413 - playService.stopTalk(device, channelId, param.isRegist()); 419 + } else {
  420 + logger.info("[语音对讲] 未找到设备:{}", deviceId);
414 } 421 }
415 - } else{  
416 - logger.info("[语音对讲] 未找到设备:{}", deviceId);  
417 } 422 }
418 } 423 }
419 - }  
420 424
421 - }else{  
422 - if (!"rtp".equals(param.getApp())){  
423 - String type = OriginType.values()[param.getOriginType()].getType();  
424 - MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());  
425 -  
426 - if (mediaServerItem != null){  
427 - if (param.isRegist()) {  
428 - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());  
429 - String callId = null;  
430 - if (streamAuthorityInfo != null) {  
431 - callId = streamAuthorityInfo.getCallId();  
432 - }  
433 - StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem,  
434 - param.getApp(), param.getStream(), param.getTracks(), callId);  
435 - param.setStreamInfo(new StreamContent(streamInfoByAppAndStream));  
436 - redisCatchStorage.addStream(mediaServerItem, type, param.getApp(), param.getStream(), param);  
437 - if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal()  
438 - || param.getOriginType() == OriginType.RTMP_PUSH.ordinal()  
439 - || param.getOriginType() == OriginType.RTC_PUSH.ordinal() ) {  
440 - param.setSeverId(userSetting.getServerId());  
441 - zlmMediaListManager.addPush(param);  
442 - }  
443 - }else {  
444 - // 兼容流注销时类型从redis记录获取  
445 - OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(  
446 - param.getApp(), param.getStream(), param.getMediaServerId());  
447 - if (onStreamChangedHookParam != null) {  
448 - type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType();  
449 - redisCatchStorage.removeStream(mediaServerItem.getId(), type, param.getApp(), param.getStream());  
450 - }  
451 - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());  
452 - if (gbStream != null) { 425 + } else {
  426 + if (!"rtp".equals(param.getApp())) {
  427 + String type = OriginType.values()[param.getOriginType()].getType();
  428 + MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
  429 +
  430 + if (mediaServerItem != null) {
  431 + if (param.isRegist()) {
  432 + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
  433 + String callId = null;
  434 + if (streamAuthorityInfo != null) {
  435 + callId = streamAuthorityInfo.getCallId();
  436 + }
  437 + StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem,
  438 + param.getApp(), param.getStream(), param.getTracks(), callId);
  439 + param.setStreamInfo(new StreamContent(streamInfoByAppAndStream));
  440 + redisCatchStorage.addStream(mediaServerItem, type, param.getApp(), param.getStream(), param);
  441 + if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
  442 + || param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
  443 + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
  444 + param.setSeverId(userSetting.getServerId());
  445 + zlmMediaListManager.addPush(param);
  446 + }
  447 + } else {
  448 + // 兼容流注销时类型从redis记录获取
  449 + OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(
  450 + param.getApp(), param.getStream(), param.getMediaServerId());
  451 + if (onStreamChangedHookParam != null) {
  452 + type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType();
  453 + redisCatchStorage.removeStream(mediaServerItem.getId(), type, param.getApp(), param.getStream());
  454 + }
  455 + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
  456 + if (gbStream != null) {
453 // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); 457 // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
454 } 458 }
455 zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); 459 zlmMediaListManager.removeMedia(param.getApp(), param.getStream());
456 } 460 }
  461 + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
  462 + if (gbStream != null) {
  463 + eventPublisher.catalogEventPublishForStream(null, gbStream, param.isRegist() ? CatalogEvent.ON : CatalogEvent.OFF);
  464 + }
457 if (type != null) { 465 if (type != null) {
458 // 发送流变化redis消息 466 // 发送流变化redis消息
459 JSONObject jsonObject = new JSONObject(); 467 JSONObject jsonObject = new JSONObject();
@@ -466,38 +474,35 @@ public class ZLMHttpHookListener { @@ -466,38 +474,35 @@ public class ZLMHttpHookListener {
466 } 474 }
467 } 475 }
468 } 476 }
469 - }  
470 - if (!param.isRegist()) {  
471 - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());  
472 - if (sendRtpItems.size() > 0) {  
473 - for (SendRtpItem sendRtpItem : sendRtpItems) {  
474 - if (sendRtpItem.getApp().equals(param.getApp())) {  
475 - String platformId = sendRtpItem.getPlatformId();  
476 - ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);  
477 - Device device = deviceService.getDevice(platformId);  
478 -  
479 -  
480 - if (platform != null) {  
481 - try { 477 + if (!param.isRegist()) {
  478 + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());
  479 + if (sendRtpItems.size() > 0) {
  480 + for (SendRtpItem sendRtpItem : sendRtpItems) {
  481 + if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) {
  482 + String platformId = sendRtpItem.getPlatformId();
  483 + ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
  484 + Device device = deviceService.getDevice(platformId);
  485 +
  486 + try {
  487 + if (platform != null) {
482 commanderFroPlatform.streamByeCmd(platform, sendRtpItem); 488 commanderFroPlatform.streamByeCmd(platform, sendRtpItem);
483 - } catch (SipException | InvalidArgumentException | ParseException e) {  
484 - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());  
485 - }  
486 - } else {  
487 - try { 489 + redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(),
  490 + sendRtpItem.getCallId(), sendRtpItem.getStream());
  491 + } else {
488 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); 492 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId());
489 - } catch (SipException | InvalidArgumentException | ParseException |  
490 - SsrcTransactionNotFoundException e) {  
491 - logger.error("[命令发送失败] 发送BYE: {}", e.getMessage());  
492 } 493 }
  494 + } catch (SipException | InvalidArgumentException | ParseException |
  495 + SsrcTransactionNotFoundException e) {
  496 + logger.error("[命令发送失败] 发送BYE: {}", e.getMessage());
493 } 497 }
  498 + }
494 } 499 }
495 } 500 }
496 } 501 }
497 } 502 }
  503 +
498 } 504 }
499 }); 505 });
500 -  
501 return HookResult.SUCCESS(); 506 return HookResult.SUCCESS();
502 } 507 }
503 508
@@ -508,82 +513,65 @@ public class ZLMHttpHookListener { @@ -508,82 +513,65 @@ public class ZLMHttpHookListener {
508 @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8") 513 @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8")
509 public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) { 514 public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) {
510 515
511 - logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());  
512 - JSONObject ret = new JSONObject();  
513 - ret.put("code", 0);  
514 - // 国标类型的流  
515 - if ("rtp".equals(param.getApp())){  
516 - ret.put("close", userSetting.getStreamOnDemand());  
517 - // 国标流, 点播/录像回放/录像下载  
518 - StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(param.getStream());  
519 - // 点播  
520 - if (streamInfoForPlayCatch != null) {  
521 - // 收到无人观看说明流也没有在往上级推送  
522 - if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) {  
523 - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(streamInfoForPlayCatch.getChannelId());  
524 - if (sendRtpItems.size() > 0) {  
525 - for (SendRtpItem sendRtpItem : sendRtpItems) {  
526 - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());  
527 - if (parentPlatform == null) {  
528 - continue;  
529 - }  
530 - try {  
531 - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());  
532 - } catch (SipException | InvalidArgumentException | ParseException e) {  
533 - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());  
534 - }  
535 - redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),  
536 - sendRtpItem.getCallId(), sendRtpItem.getStream());  
537 - }  
538 - }  
539 - }  
540 - Device device = deviceService.getDevice(streamInfoForPlayCatch.getDeviceID());  
541 - if (device != null) {  
542 - try {  
543 - cmder.streamByeCmd(device, streamInfoForPlayCatch.getChannelId(),  
544 - streamInfoForPlayCatch.getStream(), null);  
545 - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {  
546 - logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage());  
547 - }  
548 - }  
549 -  
550 - redisCatchStorage.stopPlay(streamInfoForPlayCatch);  
551 - storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());  
552 - return ret;  
553 - }  
554 - // 录像回放  
555 - StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, param.getStream(), null);  
556 - if (streamInfoForPlayBackCatch != null) {  
557 - if (streamInfoForPlayBackCatch.isPause()) { 516 + logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(),
  517 + param.getApp(), param.getStream());
  518 + JSONObject ret = new JSONObject();
  519 + ret.put("code", 0);
  520 + // 国标类型的流
  521 + if ("rtp".equals(param.getApp())) {
  522 + ret.put("close", userSetting.getStreamOnDemand());
  523 + // 国标流, 点播/录像回放/录像下载
  524 +// StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(param.getStream());
  525 +
  526 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
  527 + // 点播
  528 + if (inviteInfo != null) {
  529 + // 录像下载
  530 + if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {
558 ret.put("close", false); 531 ret.put("close", false);
559 - } else {  
560 - Device device = deviceService.getDevice(streamInfoForPlayBackCatch.getDeviceID());  
561 - if (device != null) {  
562 - try {  
563 - cmder.streamByeCmd(device, streamInfoForPlayBackCatch.getChannelId(),  
564 - streamInfoForPlayBackCatch.getStream(), null);  
565 - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {  
566 - logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage()); 532 + return ret;
  533 + }
  534 + // 收到无人观看说明流也没有在往上级推送
  535 + if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {
  536 + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(
  537 + inviteInfo.getChannelId());
  538 + if (sendRtpItems.size() > 0) {
  539 + for (SendRtpItem sendRtpItem : sendRtpItems) {
  540 + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
  541 + try {
  542 + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
  543 + } catch (SipException | InvalidArgumentException | ParseException e) {
  544 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  545 + }
  546 + redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
  547 + sendRtpItem.getCallId(), sendRtpItem.getStream());
567 } 548 }
568 } 549 }
569 - redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(),  
570 - streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null);  
571 } 550 }
572 - return ret;  
573 - }  
574 - // 录像下载  
575 - StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null, param.getStream(), null);  
576 - // 进行录像下载时无人观看不断流  
577 - if (streamInfoForDownload != null) {  
578 - ret.put("close", false); 551 + Device device = deviceService.getDevice(inviteInfo.getDeviceId());
  552 + if (device != null) {
  553 + try {
  554 + if (inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()) != null) {
  555 + cmder.streamByeCmd(device, inviteInfo.getChannelId(),
  556 + inviteInfo.getStream(), null);
  557 + }
  558 + } catch (InvalidArgumentException | ParseException | SipException |
  559 + SsrcTransactionNotFoundException e) {
  560 + logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage());
  561 + }
  562 + }
  563 +
  564 + inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(),
  565 + inviteInfo.getChannelId(), inviteInfo.getStream());
  566 + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
579 return ret; 567 return ret;
580 } 568 }
581 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, param.getStream(), null); 569 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, param.getStream(), null);
582 - if ("talk".equals(sendRtpItem.getApp())){ 570 + if ("talk".equals(sendRtpItem.getApp())) {
583 ret.put("close", false); 571 ret.put("close", false);
584 return ret; 572 return ret;
585 } 573 }
586 - }else if ("talk".equals(param.getApp()) || "broadcast".equals(param.getApp())){ 574 + } else if ("talk".equals(param.getApp()) || "broadcast".equals(param.getApp())) {
587 ret.put("close", false); 575 ret.put("close", false);
588 } else { 576 } else {
589 // 非国标流 推流/拉流代理 577 // 非国标流 推流/拉流代理
@@ -652,6 +640,7 @@ public class ZLMHttpHookListener { @@ -652,6 +640,7 @@ public class ZLMHttpHookListener {
652 return defaultResult; 640 return defaultResult;
653 } 641 }
654 logger.info("[ZLM HOOK] 流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream()); 642 logger.info("[ZLM HOOK] 流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
  643 +
655 RequestMessage msg = new RequestMessage(); 644 RequestMessage msg = new RequestMessage();
656 String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; 645 String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
657 boolean exist = resultHolder.exist(key, null); 646 boolean exist = resultHolder.exist(key, null);
@@ -659,31 +648,22 @@ public class ZLMHttpHookListener { @@ -659,31 +648,22 @@ public class ZLMHttpHookListener {
659 String uuid = UUID.randomUUID().toString(); 648 String uuid = UUID.randomUUID().toString();
660 msg.setId(uuid); 649 msg.setId(uuid);
661 DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); 650 DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
662 - DeferredResultEx<HookResult> deferredResultEx = new DeferredResultEx<>(result);  
663 651
664 result.onTimeout(() -> { 652 result.onTimeout(() -> {
665 - logger.info("点播接口等待超时"); 653 + logger.info("[ZLM HOOK] 自动点播, 等待超时");
666 // 释放rtpserver 654 // 释放rtpserver
667 msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时")); 655 msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
668 resultHolder.invokeResult(msg); 656 resultHolder.invokeResult(msg);
669 }); 657 });
670 - // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误  
671 - deferredResultEx.setFilter(result1 -> {  
672 - WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>) result1;  
673 - HookResult resultForEnd = new HookResult();  
674 - resultForEnd.setCode(wvpResult1.getCode());  
675 - resultForEnd.setMsg(wvpResult1.getMsg());  
676 - return resultForEnd;  
677 - });  
678 658
679 // 录像查询以channelId作为deviceId查询 659 // 录像查询以channelId作为deviceId查询
680 - resultHolder.put(key, uuid, deferredResultEx); 660 + resultHolder.put(key, uuid, result);
681 661
682 if (!exist) { 662 if (!exist) {
683 - playService.play(mediaInfo, deviceId, channelId, null, eventResult -> {  
684 - msg.setData(new HookResult(eventResult.statusCode, eventResult.msg)); 663 + playService.play(mediaInfo, deviceId, channelId, (code, message, data) -> {
  664 + msg.setData(new HookResult(code, message));
685 resultHolder.invokeResult(msg); 665 resultHolder.invokeResult(msg);
686 - }, null); 666 + });
687 } 667 }
688 return result; 668 return result;
689 } else { 669 } else {
@@ -740,6 +720,7 @@ public class ZLMHttpHookListener { @@ -740,6 +720,7 @@ public class ZLMHttpHookListener {
740 if (sendRtpItems.size() > 0) { 720 if (sendRtpItems.size() > 0) {
741 for (SendRtpItem sendRtpItem : sendRtpItems) { 721 for (SendRtpItem sendRtpItem : sendRtpItems) {
742 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); 722 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
  723 + ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
743 try { 724 try {
744 commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId()); 725 commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
745 } catch (SipException | InvalidArgumentException | ParseException e) { 726 } catch (SipException | InvalidArgumentException | ParseException e) {
@@ -759,7 +740,8 @@ public class ZLMHttpHookListener { @@ -759,7 +740,8 @@ public class ZLMHttpHookListener {
759 */ 740 */
760 @ResponseBody 741 @ResponseBody
761 @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8") 742 @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8")
762 - public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam param) { 743 + public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam
  744 + param) {
763 logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc()); 745 logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc());
764 746
765 taskExecutor.execute(() -> { 747 taskExecutor.execute(() -> {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
@@ -97,7 +97,8 @@ public class ZLMMediaListManager { @@ -97,7 +97,8 @@ public class ZLMMediaListManager {
97 public void sendStreamEvent(String app, String stream, String mediaServerId) { 97 public void sendStreamEvent(String app, String stream, String mediaServerId) {
98 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); 98 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
99 // 查看推流状态 99 // 查看推流状态
100 - if (zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream)) { 100 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream);
  101 + if (streamReady != null && streamReady) {
101 ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(app, stream); 102 ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(app, stream);
102 if (channelOnlineEventLister != null) { 103 if (channelOnlineEventLister != null) {
103 try { 104 try {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -25,6 +25,8 @@ public class ZLMRESTfulUtils { @@ -25,6 +25,8 @@ public class ZLMRESTfulUtils {
25 25
26 private OkHttpClient client; 26 private OkHttpClient client;
27 27
  28 +
  29 +
28 public interface RequestCallback{ 30 public interface RequestCallback{
29 void run(JSONObject response); 31 void run(JSONObject response);
30 } 32 }
@@ -279,6 +281,10 @@ public class ZLMRESTfulUtils { @@ -279,6 +281,10 @@ public class ZLMRESTfulUtils {
279 return sendPost(mediaServerItem, "closeRtpServer",param, null); 281 return sendPost(mediaServerItem, "closeRtpServer",param, null);
280 } 282 }
281 283
  284 + public void closeRtpServer(MediaServerItem mediaServerItem, Map<String, Object> param, RequestCallback callback) {
  285 + sendPost(mediaServerItem, "closeRtpServer",param, callback);
  286 + }
  287 +
282 public JSONObject listRtpServer(MediaServerItem mediaServerItem) { 288 public JSONObject listRtpServer(MediaServerItem mediaServerItem) {
283 return sendPost(mediaServerItem, "listRtpServer",null, null); 289 return sendPost(mediaServerItem, "listRtpServer",null, null);
284 } 290 }
@@ -353,4 +359,19 @@ public class ZLMRESTfulUtils { @@ -353,4 +359,19 @@ public class ZLMRESTfulUtils {
353 param.put("stream_id", streamId); 359 param.put("stream_id", streamId);
354 return sendPost(mediaServerItem, "resumeRtpCheck",param, null); 360 return sendPost(mediaServerItem, "resumeRtpCheck",param, null);
355 } 361 }
  362 +
  363 + public JSONObject connectRtpServer(MediaServerItem mediaServerItem, String dst_url, int dst_port, String stream_id) {
  364 + Map<String, Object> param = new HashMap<>(1);
  365 + param.put("dst_url", dst_url);
  366 + param.put("dst_port", dst_port);
  367 + param.put("stream_id", stream_id);
  368 + return sendPost(mediaServerItem, "connectRtpServer",param, null);
  369 + }
  370 +
  371 + public JSONObject updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc) {
  372 + Map<String, Object> param = new HashMap<>(1);
  373 + param.put("ssrc", ssrc);
  374 + param.put("stream_id", streamId);
  375 + return sendPost(mediaServerItem, "updateRtpServerSSRC",param, null);
  376 + }
356 } 377 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.zlm; @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.zlm;
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.alibaba.fastjson2.JSONArray; 4 import com.alibaba.fastjson2.JSONArray;
5 import com.alibaba.fastjson2.JSONObject; 5 import com.alibaba.fastjson2.JSONObject;
  6 +import com.genersoft.iot.vmp.common.CommonCallback;
6 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
7 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 8 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
8 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; 9 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
@@ -92,7 +93,17 @@ public class ZLMRTPServerFactory { @@ -92,7 +93,17 @@ public class ZLMRTPServerFactory {
92 return result; 93 return result;
93 } 94 }
94 95
95 - public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port, Boolean onlyAuto) { 96 + /**
  97 + * 开启rtpServer
  98 + * @param mediaServerItem zlm服务实例
  99 + * @param streamId 流Id
  100 + * @param ssrc ssrc
  101 + * @param port 端口, 0/null为使用随机
  102 + * @param reUsePort 是否重用端口
  103 + * @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。
  104 + * @return
  105 + */
  106 + public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode) {
96 int result = -1; 107 int result = -1;
97 // 查询此rtp server 是否已经存在 108 // 查询此rtp server 是否已经存在
98 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId); 109 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
@@ -108,7 +119,7 @@ public class ZLMRTPServerFactory { @@ -108,7 +119,7 @@ public class ZLMRTPServerFactory {
108 JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(mediaServerItem, param); 119 JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(mediaServerItem, param);
109 if (jsonObject != null ) { 120 if (jsonObject != null ) {
110 if (jsonObject.getInteger("code") == 0) { 121 if (jsonObject.getInteger("code") == 0) {
111 - return createRTPServer(mediaServerItem, streamId, ssrc, port, onlyAuto); 122 + return createRTPServer(mediaServerItem, streamId, ssrc, port,onlyAuto, reUsePort, tcpMode);
112 }else { 123 }else {
113 logger.warn("[开启rtpServer], 重启RtpServer错误"); 124 logger.warn("[开启rtpServer], 重启RtpServer错误");
114 } 125 }
@@ -122,8 +133,14 @@ public class ZLMRTPServerFactory { @@ -122,8 +133,14 @@ public class ZLMRTPServerFactory {
122 133
123 Map<String, Object> param = new HashMap<>(); 134 Map<String, Object> param = new HashMap<>();
124 135
125 - param.put("enable_tcp", 1); 136 + if (tcpMode == null) {
  137 + tcpMode = 0;
  138 + }
  139 + param.put("tcp_mode", tcpMode);
126 param.put("stream_id", streamId); 140 param.put("stream_id", streamId);
  141 + if (reUsePort != null) {
  142 + param.put("re_use_port", reUsePort?"1":"0");
  143 + }
127 // 推流端口设置0则使用随机端口 144 // 推流端口设置0则使用随机端口
128 if (port == null) { 145 if (port == null) {
129 param.put("port", 0); 146 param.put("port", 0);
@@ -169,6 +186,31 @@ public class ZLMRTPServerFactory { @@ -169,6 +186,31 @@ public class ZLMRTPServerFactory {
169 return result; 186 return result;
170 } 187 }
171 188
  189 + public void closeRtpServer(MediaServerItem serverItem, String streamId, CommonCallback<Boolean> callback) {
  190 + if (serverItem == null) {
  191 + callback.run(false);
  192 + return;
  193 + }
  194 + Map<String, Object> param = new HashMap<>();
  195 + param.put("stream_id", streamId);
  196 + zlmresTfulUtils.closeRtpServer(serverItem, param, jsonObject -> {
  197 + if (jsonObject != null ) {
  198 + if (jsonObject.getInteger("code") == 0) {
  199 + callback.run(jsonObject.getInteger("hit") == 1);
  200 + return;
  201 + }else {
  202 + logger.error("关闭RTP Server 失败: " + jsonObject.getString("msg"));
  203 + }
  204 + }else {
  205 + // 检查ZLM状态
  206 + logger.error("关闭RTP Server 失败: 请检查ZLM服务");
  207 + }
  208 + callback.run(false);
  209 + });
  210 +
  211 +
  212 + }
  213 +
172 214
173 /** 215 /**
174 * 创建一个国标推流 216 * 创建一个国标推流
@@ -256,11 +298,14 @@ public class ZLMRTPServerFactory { @@ -256,11 +298,14 @@ public class ZLMRTPServerFactory {
256 if (jsonObject.getInteger("code") == 0) { 298 if (jsonObject.getInteger("code") == 0) {
257 localPort = jsonObject.getInteger("port"); 299 localPort = jsonObject.getInteger("port");
258 HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, serverItem.getId()); 300 HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, serverItem.getId());
259 - // 订阅 zlm启动事件, 新的zlm也会从这里进入系统  
260 hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout, 301 hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout,
261 (MediaServerItem mediaServerItem, JSONObject response)->{ 302 (MediaServerItem mediaServerItem, JSONObject response)->{
262 - logger.info("[保持端口] {}->监听端口到期继续保持监听", ssrc);  
263 - keepPort(serverItem, ssrc); 303 + logger.info("[上级点播] {}->监听端口到期继续保持监听", ssrc);
  304 + int port = keepPort(serverItem, ssrc);
  305 + if (port == 0) {
  306 + logger.info("[上级点播] {}->监听端口失败,移除监听", ssrc);
  307 + hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
  308 + }
264 }); 309 });
265 logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort); 310 logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort);
266 logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort); 311 logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort);
@@ -305,6 +350,9 @@ public class ZLMRTPServerFactory { @@ -305,6 +350,9 @@ public class ZLMRTPServerFactory {
305 */ 350 */
306 public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) { 351 public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) {
307 JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtsp", streamId); 352 JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtsp", streamId);
  353 + if (mediaInfo.getInteger("code") == -2) {
  354 + return null;
  355 + }
308 return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")); 356 return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
309 } 357 }
310 358
@@ -313,8 +361,10 @@ public class ZLMRTPServerFactory { @@ -313,8 +361,10 @@ public class ZLMRTPServerFactory {
313 */ 361 */
314 public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) { 362 public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) {
315 JSONObject mediaInfo = zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId); 363 JSONObject mediaInfo = zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId);
316 - return mediaInfo != null && (mediaInfo.getInteger("code") == 0  
317 - 364 + if (mediaInfo == null || (mediaInfo.getInteger("code") == -2)) {
  365 + return null;
  366 + }
  367 + return (mediaInfo.getInteger("code") == 0
318 && mediaInfo.getJSONArray("data") != null 368 && mediaInfo.getJSONArray("data") != null
319 && mediaInfo.getJSONArray("data").size() > 0); 369 && mediaInfo.getJSONArray("data").size() > 0);
320 } 370 }
@@ -406,4 +456,19 @@ public class ZLMRTPServerFactory { @@ -406,4 +456,19 @@ public class ZLMRTPServerFactory {
406 } 456 }
407 return startSendRtpStreamResult; 457 return startSendRtpStreamResult;
408 } 458 }
  459 +
  460 + public Boolean updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc) {
  461 + boolean result = false;
  462 + JSONObject jsonObject = zlmresTfulUtils.updateRtpServerSSRC(mediaServerItem, streamId, ssrc);
  463 + if (jsonObject == null) {
  464 + logger.error("[更新RTPServer] 失败: 请检查ZLM服务");
  465 + } else if (jsonObject.getInteger("code") == 0) {
  466 + result= true;
  467 + logger.info("[更新RTPServer] 成功");
  468 + } else {
  469 + logger.error("[更新RTPServer] 失败: {}, streamId:{},ssrc:{}->\r\n{}",jsonObject.getString("msg"),
  470 + streamId, ssrc, jsonObject);
  471 + }
  472 + return result;
  473 + }
409 } 474 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java
@@ -100,7 +100,10 @@ public class ZlmHttpHookSubscribe { @@ -100,7 +100,10 @@ public class ZlmHttpHookSubscribe {
100 100
101 if (!CollectionUtils.isEmpty(entriesToRemove)) { 101 if (!CollectionUtils.isEmpty(entriesToRemove)) {
102 for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entriesToRemove) { 102 for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entriesToRemove) {
103 - entries.remove(entry); 103 + eventMap.remove(entry.getKey());
  104 + }
  105 + if (eventMap.size() == 0) {
  106 + allSubscribes.remove(hookSubscribe.getHookType());
104 } 107 }
105 } 108 }
106 109
@@ -136,9 +139,9 @@ public class ZlmHttpHookSubscribe { @@ -136,9 +139,9 @@ public class ZlmHttpHookSubscribe {
136 /** 139 /**
137 * 对订阅数据进行过期清理 140 * 对订阅数据进行过期清理
138 */ 141 */
139 - @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次 142 +// @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次
  143 + @Scheduled(fixedRate = 2 * 1000)
140 public void execute(){ 144 public void execute(){
141 -  
142 Instant instant = Instant.now().minusMillis(TimeUnit.MINUTES.toMillis(5)); 145 Instant instant = Instant.now().minusMillis(TimeUnit.MINUTES.toMillis(5));
143 int total = 0; 146 int total = 0;
144 for (HookType hookType : allSubscribes.keySet()) { 147 for (HookType hookType : allSubscribes.keySet()) {
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
1 package com.genersoft.iot.vmp.media.zlm.dto; 1 package com.genersoft.iot.vmp.media.zlm.dto;
2 2
3 3
4 -import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;  
5 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; 4 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
6 import io.swagger.v3.oas.annotations.media.Schema; 5 import io.swagger.v3.oas.annotations.media.Schema;
7 import org.springframework.util.ObjectUtils; 6 import org.springframework.util.ObjectUtils;
8 7
9 -import java.util.HashMap;  
10 -  
11 @Schema(description = "流媒体服务信息") 8 @Schema(description = "流媒体服务信息")
12 public class MediaServerItem{ 9 public class MediaServerItem{
13 10
@@ -80,20 +77,10 @@ public class MediaServerItem{ @@ -80,20 +77,10 @@ public class MediaServerItem{
80 @Schema(description = "是否是默认ZLM") 77 @Schema(description = "是否是默认ZLM")
81 private boolean defaultServer; 78 private boolean defaultServer;
82 79
83 - @Schema(description = "SSRC信息")  
84 - private SsrcConfig ssrcConfig;  
85 -  
86 @Schema(description = "当前使用到的端口") 80 @Schema(description = "当前使用到的端口")
87 private int currentPort; 81 private int currentPort;
88 82
89 83
90 - /**  
91 - * 每一台ZLM都有一套独立的SSRC列表  
92 - * 在ApplicationCheckRunner里对mediaServerSsrcMap进行初始化  
93 - */  
94 - @Schema(description = "ID")  
95 - private HashMap<String, SsrcConfig> mediaServerSsrcMap;  
96 -  
97 public MediaServerItem() { 84 public MediaServerItem() {
98 } 85 }
99 86
@@ -279,22 +266,6 @@ public class MediaServerItem{ @@ -279,22 +266,6 @@ public class MediaServerItem{
279 this.updateTime = updateTime; 266 this.updateTime = updateTime;
280 } 267 }
281 268
282 - public HashMap<String, SsrcConfig> getMediaServerSsrcMap() {  
283 - return mediaServerSsrcMap;  
284 - }  
285 -  
286 - public void setMediaServerSsrcMap(HashMap<String, SsrcConfig> mediaServerSsrcMap) {  
287 - this.mediaServerSsrcMap = mediaServerSsrcMap;  
288 - }  
289 -  
290 - public SsrcConfig getSsrcConfig() {  
291 - return ssrcConfig;  
292 - }  
293 -  
294 - public void setSsrcConfig(SsrcConfig ssrcConfig) {  
295 - this.ssrcConfig = ssrcConfig;  
296 - }  
297 -  
298 public int getCurrentPort() { 269 public int getCurrentPort() {
299 return currentPort; 270 return currentPort;
300 } 271 }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java
@@ -18,6 +18,10 @@ public class HookResult { @@ -18,6 +18,10 @@ public class HookResult {
18 return new HookResult(0, "success"); 18 return new HookResult(0, "success");
19 } 19 }
20 20
  21 + public static HookResult Fail(){
  22 + return new HookResult(-1, "fail");
  23 + }
  24 +
21 public int getCode() { 25 public int getCode() {
22 return code; 26 return code;
23 } 27 }
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
@@ -56,4 +56,35 @@ public interface IDeviceChannelService { @@ -56,4 +56,35 @@ public interface IDeviceChannelService {
56 * 查询通道所属的设备 56 * 查询通道所属的设备
57 */ 57 */
58 List<Device> getDeviceByChannelId(String channelId); 58 List<Device> getDeviceByChannelId(String channelId);
  59 +
  60 + /**
  61 + * 批量删除通道
  62 + * @param deleteChannelList 待删除的通道列表
  63 + */
  64 + int deleteChannels(List<DeviceChannel> deleteChannelList);
  65 +
  66 + /**
  67 + * 批量上线
  68 + */
  69 + int channelsOnline(List<DeviceChannel> channels);
  70 +
  71 + /**
  72 + * 批量下线
  73 + */
  74 + int channelsOffline(List<DeviceChannel> channels);
  75 +
  76 + /**
  77 + * 获取一个通道
  78 + */
  79 + DeviceChannel getOne(String deviceId, String channelId);
  80 +
  81 + /**
  82 + * 直接批量更新通道
  83 + */
  84 + void batchUpdateChannel(List<DeviceChannel> channels);
  85 +
  86 + /**
  87 + * 直接批量添加
  88 + */
  89 + void batchAddChannel(List<DeviceChannel> deviceChannels);
59 } 90 }
src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service;
  2 +
  3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
  5 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  6 +
  7 +/**
  8 + * 记录国标点播的状态,包括实时预览,下载,录像回放
  9 + */
  10 +public interface IInviteStreamService {
  11 +
  12 + /**
  13 + * 更新点播的状态信息
  14 + */
  15 + void updateInviteInfo(InviteInfo inviteInfo);
  16 +
  17 + /**
  18 + * 获取点播的状态信息
  19 + */
  20 + InviteInfo getInviteInfo(InviteSessionType type,
  21 + String deviceId,
  22 + String channelId,
  23 + String stream);
  24 +
  25 + /**
  26 + * 移除点播的状态信息
  27 + */
  28 + void removeInviteInfo(InviteSessionType type,
  29 + String deviceId,
  30 + String channelId,
  31 + String stream);
  32 + /**
  33 + * 移除点播的状态信息
  34 + */
  35 + void removeInviteInfo(InviteInfo inviteInfo);
  36 + /**
  37 + * 移除点播的状态信息
  38 + */
  39 + void removeInviteInfoByDeviceAndChannel(InviteSessionType inviteSessionType, String deviceId, String channelId);
  40 +
  41 + /**
  42 + * 获取点播的状态信息
  43 + */
  44 + InviteInfo getInviteInfoByDeviceAndChannel(InviteSessionType type,
  45 + String deviceId,
  46 + String channelId);
  47 +
  48 + /**
  49 + * 获取点播的状态信息
  50 + */
  51 + InviteInfo getInviteInfoByStream(InviteSessionType type, String stream);
  52 +
  53 +
  54 + /**
  55 + * 添加一个invite回调
  56 + */
  57 + void once(InviteSessionType type, String deviceId, String channelId, String stream, InviteErrorCallback<Object> callback);
  58 +
  59 + /**
  60 + * 调用一个invite回调
  61 + */
  62 + void call(InviteSessionType type, String deviceId, String channelId, String stream, int code, String msg, Object data);
  63 +
  64 + /**
  65 + * 清空一个设备的所有invite信息
  66 + */
  67 + void clearInviteInfo(String deviceId);
  68 +}
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
1 package com.genersoft.iot.vmp.service; 1 package com.genersoft.iot.vmp.service;
2 2
  3 +import com.genersoft.iot.vmp.common.CommonCallback;
3 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; 4 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
4 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 5 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
5 import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData; 6 import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
@@ -43,14 +44,16 @@ public interface IMediaServerService { @@ -43,14 +44,16 @@ public interface IMediaServerService {
43 44
44 void updateVmServer(List<MediaServerItem> mediaServerItemList); 45 void updateVmServer(List<MediaServerItem> mediaServerItemList);
45 46
46 - SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback);  
47 -  
48 - SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback); 47 + SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck,
  48 + boolean isPlayback, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode);
49 49
50 SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port, Boolean onlyAuto); 50 SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port, Boolean onlyAuto);
51 51
52 void closeRTPServer(MediaServerItem mediaServerItem, String streamId); 52 void closeRTPServer(MediaServerItem mediaServerItem, String streamId);
53 53
  54 + void closeRTPServer(MediaServerItem mediaServerItem, String streamId, CommonCallback<Boolean> callback);
  55 + Boolean updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc);
  56 +
54 void closeRTPServer(String mediaServerId, String streamId); 57 void closeRTPServer(String mediaServerId, String streamId);
55 58
56 void clearRTPServer(MediaServerItem mediaServerItem); 59 void clearRTPServer(MediaServerItem mediaServerItem);
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -3,12 +3,11 @@ package com.genersoft.iot.vmp.service; @@ -3,12 +3,11 @@ package com.genersoft.iot.vmp.service;
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
4 import com.genersoft.iot.vmp.common.StreamInfo; 4 import com.genersoft.iot.vmp.common.StreamInfo;
5 import com.genersoft.iot.vmp.conf.exception.ServiceException; 5 import com.genersoft.iot.vmp.conf.exception.ServiceException;
6 -import com.genersoft.iot.vmp.gb28181.bean.*;  
7 -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;  
8 -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 6 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  7 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  8 +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
9 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 9 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
10 -import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;  
11 -import com.genersoft.iot.vmp.service.bean.PlayBackCallback; 10 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
12 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 11 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
13 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; 12 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
14 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; 13 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
@@ -25,12 +24,11 @@ import java.util.Map; @@ -25,12 +24,11 @@ import java.util.Map;
25 */ 24 */
26 public interface IPlayService { 25 public interface IPlayService {
27 26
28 - void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId);  
29 -  
30 void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 27 void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
31 - ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,  
32 - InviteTimeOutCallback timeoutCallback);  
33 - void play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent, Runnable timeoutCallback); 28 + InviteErrorCallback<Object> callback);
  29 + SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, InviteErrorCallback<Object> callback);
  30 +
  31 + StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId);
34 32
35 MediaServerItem getNewMediaServerItem(Device device); 33 MediaServerItem getNewMediaServerItem(Device device);
36 34
@@ -39,15 +37,13 @@ public interface IPlayService { @@ -39,15 +37,13 @@ public interface IPlayService {
39 */ 37 */
40 MediaServerItem getNewMediaServerItemHasAssist(Device device); 38 MediaServerItem getNewMediaServerItemHasAssist(Device device);
41 39
42 - void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String toString);  
43 -  
44 - void playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback);  
45 - void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); 40 + void playBack(String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
  41 + void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
46 42
47 void zlmServerOffline(String mediaServerId); 43 void zlmServerOffline(String mediaServerId);
48 44
49 - void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback);  
50 - void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); 45 + void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
  46 + void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
51 47
52 StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream); 48 StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
53 49
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCallback.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.bean;
  2 +
  3 +public interface InviteErrorCallback<T> {
  4 +
  5 + void run(int code, String msg, T data);
  6 +}
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.bean;
  2 +
  3 +/**
  4 + * 全局错误码
  5 + */
  6 +public enum InviteErrorCode {
  7 + SUCCESS(0, "成功"),
  8 + ERROR_FOR_SIGNALLING_TIMEOUT(-1, "信令超时"),
  9 + ERROR_FOR_STREAM_TIMEOUT(-2, "收流超时"),
  10 + ERROR_FOR_RESOURCE_EXHAUSTION(-3, "资源耗尽"),
  11 + ERROR_FOR_CATCH_DATA(-4, "缓存数据异常"),
  12 + ERROR_FOR_SIGNALLING_ERROR(-5, "收到信令错误"),
  13 + ERROR_FOR_STREAM_PARSING_EXCEPTIONS(-6, "流地址解析错误"),
  14 + ERROR_FOR_SDP_PARSING_EXCEPTIONS(-7, "SDP信息解析失败"),
  15 + ERROR_FOR_SSRC_UNAVAILABLE(-8, "SSRC不可用"),
  16 + ERROR_FOR_RESET_SSRC(-9, "重新设置收流信息失败"),
  17 + ERROR_FOR_SIP_SENDING_FAILED(-10, "命令发送失败"),
  18 + ERROR_FOR_ASSIST_NOT_READY(-11, "没有可用的assist服务"),
  19 + ERROR_FOR_PARAMETER_ERROR(-13, "参数异常");
  20 +
  21 + private final int code;
  22 + private final String msg;
  23 +
  24 + InviteErrorCode(int code, String msg) {
  25 + this.code = code;
  26 + this.msg = msg;
  27 + }
  28 +
  29 + public int getCode() {
  30 + return code;
  31 + }
  32 +
  33 + public String getMsg() {
  34 + return msg;
  35 + }
  36 +}
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
1 package com.genersoft.iot.vmp.service.impl; 1 package com.genersoft.iot.vmp.service.impl;
2 2
3 -import com.genersoft.iot.vmp.common.StreamInfo; 3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 import com.genersoft.iot.vmp.gb28181.bean.Device; 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
5 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; 6 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
6 import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; 7 import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
7 import com.genersoft.iot.vmp.service.IDeviceChannelService; 8 import com.genersoft.iot.vmp.service.IDeviceChannelService;
  9 +import com.genersoft.iot.vmp.service.IInviteStreamService;
8 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 10 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
9 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; 11 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
10 import com.genersoft.iot.vmp.storager.dao.DeviceMapper; 12 import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
@@ -33,6 +35,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -33,6 +35,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
33 private IRedisCatchStorage redisCatchStorage; 35 private IRedisCatchStorage redisCatchStorage;
34 36
35 @Autowired 37 @Autowired
  38 + private IInviteStreamService inviteStreamService;
  39 +
  40 + @Autowired
36 private DeviceChannelMapper channelMapper; 41 private DeviceChannelMapper channelMapper;
37 42
38 @Autowired 43 @Autowired
@@ -45,6 +50,8 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -45,6 +50,8 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
45 device = deviceMapper.getDeviceByDeviceId(deviceChannel.getDeviceId()); 50 device = deviceMapper.getDeviceByDeviceId(deviceChannel.getDeviceId());
46 } 51 }
47 52
  53 +
  54 +
48 if ("WGS84".equals(device.getGeoCoordSys())) { 55 if ("WGS84".equals(device.getGeoCoordSys())) {
49 deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); 56 deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
50 deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); 57 deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
@@ -76,9 +83,10 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -76,9 +83,10 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
76 public void updateChannel(String deviceId, DeviceChannel channel) { 83 public void updateChannel(String deviceId, DeviceChannel channel) {
77 String channelId = channel.getChannelId(); 84 String channelId = channel.getChannelId();
78 channel.setDeviceId(deviceId); 85 channel.setDeviceId(deviceId);
79 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);  
80 - if (streamInfo != null) {  
81 - channel.setStreamId(streamInfo.getStream()); 86 +// StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
  87 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  88 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  89 + channel.setStreamId(inviteInfo.getStreamInfo().getStream());
82 } 90 }
83 String now = DateUtil.getNow(); 91 String now = DateUtil.getNow();
84 channel.setUpdateTime(now); 92 channel.setUpdateTime(now);
@@ -104,9 +112,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -104,9 +112,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
104 if (channelList.size() == 0) { 112 if (channelList.size() == 0) {
105 for (DeviceChannel channel : channels) { 113 for (DeviceChannel channel : channels) {
106 channel.setDeviceId(deviceId); 114 channel.setDeviceId(deviceId);
107 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());  
108 - if (streamInfo != null) {  
109 - channel.setStreamId(streamInfo.getStream()); 115 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channel.getChannelId());
  116 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  117 + channel.setStreamId(inviteInfo.getStreamInfo().getStream());
110 } 118 }
111 String now = DateUtil.getNow(); 119 String now = DateUtil.getNow();
112 channel.setUpdateTime(now); 120 channel.setUpdateTime(now);
@@ -120,9 +128,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -120,9 +128,9 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
120 } 128 }
121 for (DeviceChannel channel : channels) { 129 for (DeviceChannel channel : channels) {
122 channel.setDeviceId(deviceId); 130 channel.setDeviceId(deviceId);
123 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());  
124 - if (streamInfo != null) {  
125 - channel.setStreamId(streamInfo.getStream()); 131 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channel.getChannelId());
  132 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  133 + channel.setStreamId(inviteInfo.getStreamInfo().getStream());
126 } 134 }
127 String now = DateUtil.getNow(); 135 String now = DateUtil.getNow();
128 channel.setUpdateTime(now); 136 channel.setUpdateTime(now);
@@ -207,6 +215,47 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @@ -207,6 +215,47 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
207 215
208 @Override 216 @Override
209 public List<Device> getDeviceByChannelId(String channelId) { 217 public List<Device> getDeviceByChannelId(String channelId) {
  218 +
210 return channelMapper.getDeviceByChannelId(channelId); 219 return channelMapper.getDeviceByChannelId(channelId);
211 } 220 }
  221 +
  222 + @Override
  223 + public int deleteChannels(List<DeviceChannel> deleteChannelList) {
  224 + return channelMapper.batchDel(deleteChannelList);
  225 + }
  226 +
  227 + @Override
  228 + public int channelsOnline(List<DeviceChannel> channels) {
  229 + return channelMapper.batchOnline(channels);
  230 + }
  231 +
  232 + @Override
  233 + public int channelsOffline(List<DeviceChannel> channels) {
  234 + return channelMapper.batchOffline(channels);
  235 + }
  236 +
  237 + @Override
  238 + public DeviceChannel getOne(String deviceId, String channelId){
  239 + return channelMapper.queryChannel(deviceId, channelId);
  240 + }
  241 +
  242 + @Override
  243 + public void batchUpdateChannel(List<DeviceChannel> channels) {
  244 + channelMapper.batchUpdate(channels);
  245 + for (DeviceChannel channel : channels) {
  246 + if (channel.getParentId() != null) {
  247 + channelMapper.updateChannelSubCount(channel.getDeviceId(), channel.getParentId());
  248 + }
  249 + }
  250 + }
  251 +
  252 + @Override
  253 + public void batchAddChannel(List<DeviceChannel> channels) {
  254 + channelMapper.batchAdd(channels);
  255 + for (DeviceChannel channel : channels) {
  256 + if (channel.getParentId() != null) {
  257 + channelMapper.updateChannelSubCount(channel.getDeviceId(), channel.getParentId());
  258 + }
  259 + }
  260 + }
212 } 261 }
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -15,6 +15,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; @@ -15,6 +15,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
15 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 15 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
16 import com.genersoft.iot.vmp.service.IDeviceChannelService; 16 import com.genersoft.iot.vmp.service.IDeviceChannelService;
17 import com.genersoft.iot.vmp.service.IDeviceService; 17 import com.genersoft.iot.vmp.service.IDeviceService;
  18 +import com.genersoft.iot.vmp.service.IInviteStreamService;
18 import com.genersoft.iot.vmp.service.IMediaServerService; 19 import com.genersoft.iot.vmp.service.IMediaServerService;
19 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
20 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; 21 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
@@ -60,6 +61,9 @@ public class DeviceServiceImpl implements IDeviceService { @@ -60,6 +61,9 @@ public class DeviceServiceImpl implements IDeviceService {
60 private IRedisCatchStorage redisCatchStorage; 61 private IRedisCatchStorage redisCatchStorage;
61 62
62 @Autowired 63 @Autowired
  64 + private IInviteStreamService inviteStreamService;
  65 +
  66 + @Autowired
63 private DeviceMapper deviceMapper; 67 private DeviceMapper deviceMapper;
64 68
65 @Autowired 69 @Autowired
@@ -104,7 +108,7 @@ public class DeviceServiceImpl implements IDeviceService { @@ -104,7 +108,7 @@ public class DeviceServiceImpl implements IDeviceService {
104 String now = DateUtil.getNow(); 108 String now = DateUtil.getNow();
105 if (deviceInRedis != null && deviceInDb == null) { 109 if (deviceInRedis != null && deviceInDb == null) {
106 // redis 存在脏数据 110 // redis 存在脏数据
107 - redisCatchStorage.clearCatchByDeviceId(device.getDeviceId()); 111 + inviteStreamService.clearInviteInfo(device.getDeviceId());
108 } 112 }
109 device.setUpdateTime(now); 113 device.setUpdateTime(now);
110 if (device.getKeepaliveIntervalTime() == 0) { 114 if (device.getKeepaliveIntervalTime() == 0) {
@@ -172,6 +176,11 @@ public class DeviceServiceImpl implements IDeviceService { @@ -172,6 +176,11 @@ public class DeviceServiceImpl implements IDeviceService {
172 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); 176 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId();
173 // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线 177 // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线
174 dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "首次注册后未能收到心跳"), device.getKeepaliveIntervalTime() * 1000 * 3); 178 dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "首次注册后未能收到心跳"), device.getKeepaliveIntervalTime() * 1000 * 3);
  179 + if (userSetting.getDeviceStatusNotify()) {
  180 + // 发送redis消息
  181 + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, true);
  182 + }
  183 +
175 } 184 }
176 185
177 @Override 186 @Override
@@ -200,6 +209,11 @@ public class DeviceServiceImpl implements IDeviceService { @@ -200,6 +209,11 @@ public class DeviceServiceImpl implements IDeviceService {
200 // 移除订阅 209 // 移除订阅
201 removeCatalogSubscribe(device); 210 removeCatalogSubscribe(device);
202 removeMobilePositionSubscribe(device); 211 removeMobilePositionSubscribe(device);
  212 + if (userSetting.getDeviceStatusNotify()) {
  213 + // 发送redis消息
  214 + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, false);
  215 + }
  216 +
203 List<AudioBroadcastCatch> audioBroadcastCatches = audioBroadcastManager.get(deviceId); 217 List<AudioBroadcastCatch> audioBroadcastCatches = audioBroadcastManager.get(deviceId);
204 if (audioBroadcastCatches.size() > 0) { 218 if (audioBroadcastCatches.size() > 0) {
205 for (AudioBroadcastCatch audioBroadcastCatch : audioBroadcastCatches) { 219 for (AudioBroadcastCatch audioBroadcastCatch : audioBroadcastCatches) {
@@ -512,8 +526,10 @@ public class DeviceServiceImpl implements IDeviceService { @@ -512,8 +526,10 @@ public class DeviceServiceImpl implements IDeviceService {
512 node.setBasicData(channel); 526 node.setBasicData(channel);
513 node.setParent(false); 527 node.setParent(false);
514 if (channel.getChannelId().length() > 8) { 528 if (channel.getChannelId().length() > 8) {
515 - String gbCodeType = channel.getChannelId().substring(10, 13);  
516 - node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) ); 529 + if (channel.getChannelId().length() > 13) {
  530 + String gbCodeType = channel.getChannelId().substring(10, 13);
  531 + node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) );
  532 + }
517 }else { 533 }else {
518 node.setParent(true); 534 node.setParent(true);
519 } 535 }
@@ -669,4 +685,6 @@ public class DeviceServiceImpl implements IDeviceService { @@ -669,4 +685,6 @@ public class DeviceServiceImpl implements IDeviceService {
669 public List<Device> getAll() { 685 public List<Device> getAll() {
670 return deviceMapper.getAll(); 686 return deviceMapper.getAll();
671 } 687 }
  688 +
  689 +
672 } 690 }
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.impl;
  2 +
  3 +import com.alibaba.fastjson2.JSON;
  4 +import com.genersoft.iot.vmp.common.InviteInfo;
  5 +import com.genersoft.iot.vmp.common.InviteSessionStatus;
  6 +import com.genersoft.iot.vmp.common.InviteSessionType;
  7 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  8 +import com.genersoft.iot.vmp.service.IInviteStreamService;
  9 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  10 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
  13 +import org.springframework.beans.factory.annotation.Autowired;
  14 +import org.springframework.data.redis.core.RedisTemplate;
  15 +import org.springframework.stereotype.Service;
  16 +
  17 +import java.util.List;
  18 +import java.util.Map;
  19 +import java.util.concurrent.ConcurrentHashMap;
  20 +import java.util.concurrent.CopyOnWriteArrayList;
  21 +
  22 +@Service
  23 +public class InviteStreamServiceImpl implements IInviteStreamService {
  24 +
  25 + private final Logger logger = LoggerFactory.getLogger(InviteStreamServiceImpl.class);
  26 +
  27 + private final Map<String, List<InviteErrorCallback<Object>>> inviteErrorCallbackMap = new ConcurrentHashMap<>();
  28 +
  29 + @Autowired
  30 + private RedisTemplate<Object, Object> redisTemplate;
  31 +
  32 + @Override
  33 + public void updateInviteInfo(InviteInfo inviteInfo) {
  34 + if (inviteInfo == null || (inviteInfo.getDeviceId() == null || inviteInfo.getChannelId() == null)) {
  35 + logger.warn("[更新Invite信息],参数不全: {}", JSON.toJSON(inviteInfo));
  36 + return;
  37 + }
  38 + InviteInfo inviteInfoForUpdate = null;
  39 +
  40 + if (InviteSessionStatus.ready == inviteInfo.getStatus()) {
  41 + if (inviteInfo.getDeviceId() == null
  42 + || inviteInfo.getChannelId() == null
  43 + || inviteInfo.getType() == null
  44 + || inviteInfo.getStream() == null
  45 + ) {
  46 + return;
  47 + }
  48 + inviteInfoForUpdate = inviteInfo;
  49 + } else {
  50 + InviteInfo inviteInfoInRedis = getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(),
  51 + inviteInfo.getChannelId(), inviteInfo.getStream());
  52 + if (inviteInfoInRedis == null) {
  53 + logger.warn("[更新Invite信息],未从缓存中读取到Invite信息: deviceId: {}, channel: {}, stream: {}",
  54 + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
  55 + return;
  56 + }
  57 + if (inviteInfo.getStreamInfo() != null) {
  58 + inviteInfoInRedis.setStreamInfo(inviteInfo.getStreamInfo());
  59 + }
  60 + if (inviteInfo.getSsrcInfo() != null) {
  61 + inviteInfoInRedis.setSsrcInfo(inviteInfo.getSsrcInfo());
  62 + }
  63 + if (inviteInfo.getStreamMode() != null) {
  64 + inviteInfoInRedis.setStreamMode(inviteInfo.getStreamMode());
  65 + }
  66 + if (inviteInfo.getReceiveIp() != null) {
  67 + inviteInfoInRedis.setReceiveIp(inviteInfo.getReceiveIp());
  68 + }
  69 + if (inviteInfo.getReceivePort() != null) {
  70 + inviteInfoInRedis.setReceivePort(inviteInfo.getReceivePort());
  71 + }
  72 + if (inviteInfo.getStatus() != null) {
  73 + inviteInfoInRedis.setStatus(inviteInfo.getStatus());
  74 + }
  75 +
  76 + inviteInfoForUpdate = inviteInfoInRedis;
  77 +
  78 + }
  79 + String key = VideoManagerConstants.INVITE_PREFIX +
  80 + "_" + inviteInfoForUpdate.getType() +
  81 + "_" + inviteInfoForUpdate.getDeviceId() +
  82 + "_" + inviteInfoForUpdate.getChannelId() +
  83 + "_" + inviteInfoForUpdate.getStream();
  84 + redisTemplate.opsForValue().set(key, inviteInfoForUpdate);
  85 + }
  86 +
  87 + @Override
  88 + public InviteInfo getInviteInfo(InviteSessionType type, String deviceId, String channelId, String stream) {
  89 + String key = VideoManagerConstants.INVITE_PREFIX +
  90 + "_" + (type != null ? type : "*") +
  91 + "_" + (deviceId != null ? deviceId : "*") +
  92 + "_" + (channelId != null ? channelId : "*") +
  93 + "_" + (stream != null ? stream : "*");
  94 + List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
  95 + if (scanResult.size() != 1) {
  96 + return null;
  97 + }
  98 +
  99 + return (InviteInfo) redisTemplate.opsForValue().get(scanResult.get(0));
  100 + }
  101 +
  102 + @Override
  103 + public InviteInfo getInviteInfoByDeviceAndChannel(InviteSessionType type, String deviceId, String channelId) {
  104 + return getInviteInfo(type, deviceId, channelId, null);
  105 + }
  106 +
  107 + @Override
  108 + public InviteInfo getInviteInfoByStream(InviteSessionType type, String stream) {
  109 + return getInviteInfo(type, null, null, stream);
  110 + }
  111 +
  112 + @Override
  113 + public void removeInviteInfo(InviteSessionType type, String deviceId, String channelId, String stream) {
  114 + String scanKey = VideoManagerConstants.INVITE_PREFIX +
  115 + "_" + (type != null ? type : "*") +
  116 + "_" + (deviceId != null ? deviceId : "*") +
  117 + "_" + (channelId != null ? channelId : "*") +
  118 + "_" + (stream != null ? stream : "*");
  119 + List<Object> scanResult = RedisUtil.scan(redisTemplate, scanKey);
  120 + if (scanResult.size() > 0) {
  121 + for (Object keyObj : scanResult) {
  122 + String key = (String) keyObj;
  123 + InviteInfo inviteInfo = (InviteInfo) redisTemplate.opsForValue().get(key);
  124 + if (inviteInfo == null) {
  125 + continue;
  126 + }
  127 + redisTemplate.delete(key);
  128 + inviteErrorCallbackMap.remove(buildKey(type, deviceId, channelId, inviteInfo.getStream()));
  129 + }
  130 + }
  131 + }
  132 +
  133 + @Override
  134 + public void removeInviteInfoByDeviceAndChannel(InviteSessionType inviteSessionType, String deviceId, String channelId) {
  135 + removeInviteInfo(inviteSessionType, deviceId, channelId, null);
  136 + }
  137 +
  138 + @Override
  139 + public void removeInviteInfo(InviteInfo inviteInfo) {
  140 + removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
  141 + }
  142 +
  143 + @Override
  144 + public void once(InviteSessionType type, String deviceId, String channelId, String stream, InviteErrorCallback<Object> callback) {
  145 + String key = buildKey(type, deviceId, channelId, stream);
  146 + List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
  147 + if (callbacks == null) {
  148 + callbacks = new CopyOnWriteArrayList<>();
  149 + inviteErrorCallbackMap.put(key, callbacks);
  150 + }
  151 + callbacks.add(callback);
  152 +
  153 + }
  154 +
  155 + @Override
  156 + public void call(InviteSessionType type, String deviceId, String channelId, String stream, int code, String msg, Object data) {
  157 + String key = buildKey(type, deviceId, channelId, stream);
  158 + List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
  159 + if (callbacks == null) {
  160 + return;
  161 + }
  162 + for (InviteErrorCallback<Object> callback : callbacks) {
  163 + callback.run(code, msg, data);
  164 + }
  165 + inviteErrorCallbackMap.remove(key);
  166 + }
  167 +
  168 + private String buildKey(InviteSessionType type, String deviceId, String channelId, String stream) {
  169 + String key = type + "_" + deviceId + "_" + channelId;
  170 + // 如果ssrc未null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite
  171 + if (stream != null) {
  172 + key += ("_" + stream);
  173 + }
  174 + return key;
  175 + }
  176 +
  177 +
  178 + @Override
  179 + public void clearInviteInfo(String deviceId) {
  180 + removeInviteInfo(null, deviceId, null, null);
  181 + }
  182 +}
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -3,13 +3,14 @@ package com.genersoft.iot.vmp.service.impl; @@ -3,13 +3,14 @@ package com.genersoft.iot.vmp.service.impl;
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.alibaba.fastjson2.JSONArray; 4 import com.alibaba.fastjson2.JSONArray;
5 import com.alibaba.fastjson2.JSONObject; 5 import com.alibaba.fastjson2.JSONObject;
  6 +import com.genersoft.iot.vmp.common.CommonCallback;
6 import com.genersoft.iot.vmp.common.VideoManagerConstants; 7 import com.genersoft.iot.vmp.common.VideoManagerConstants;
7 import com.genersoft.iot.vmp.conf.DynamicTask; 8 import com.genersoft.iot.vmp.conf.DynamicTask;
8 import com.genersoft.iot.vmp.conf.SipConfig; 9 import com.genersoft.iot.vmp.conf.SipConfig;
9 import com.genersoft.iot.vmp.conf.UserSetting; 10 import com.genersoft.iot.vmp.conf.UserSetting;
10 import com.genersoft.iot.vmp.conf.exception.ControllerException; 11 import com.genersoft.iot.vmp.conf.exception.ControllerException;
11 import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 12 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
12 -import com.genersoft.iot.vmp.gb28181.session.SsrcConfig; 13 +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
13 import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; 14 import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
14 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; 15 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
15 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 16 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
@@ -56,6 +57,9 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -56,6 +57,9 @@ public class MediaServerServiceImpl implements IMediaServerService {
56 @Autowired 57 @Autowired
57 private SipConfig sipConfig; 58 private SipConfig sipConfig;
58 59
  60 + @Autowired
  61 + private SSRCFactory ssrcFactory;
  62 +
59 @Value("${server.ssl.enabled:false}") 63 @Value("${server.ssl.enabled:false}")
60 private boolean sslEnabled; 64 private boolean sslEnabled;
61 65
@@ -96,6 +100,9 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -96,6 +100,9 @@ public class MediaServerServiceImpl implements IMediaServerService {
96 @Autowired 100 @Autowired
97 private RedisTemplate<Object, Object> redisTemplate; 101 private RedisTemplate<Object, Object> redisTemplate;
98 102
  103 +
  104 +
  105 +
99 /** 106 /**
100 * 初始化 107 * 初始化
101 */ 108 */
@@ -107,10 +114,8 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -107,10 +114,8 @@ public class MediaServerServiceImpl implements IMediaServerService {
107 continue; 114 continue;
108 } 115 }
109 // 更新 116 // 更新
110 - if (mediaServerItem.getSsrcConfig() == null) {  
111 - SsrcConfig ssrcConfig = new SsrcConfig(mediaServerItem.getId(), null, sipConfig.getDomain());  
112 - mediaServerItem.setSsrcConfig(ssrcConfig);  
113 - redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId(), mediaServerItem); 117 + if (ssrcFactory.hasMediaServerSSRC(mediaServerItem.getId())) {
  118 + ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null);
114 } 119 }
115 // 查询redis是否存在此mediaServer 120 // 查询redis是否存在此mediaServer
116 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId(); 121 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
@@ -122,56 +127,44 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -122,56 +127,44 @@ public class MediaServerServiceImpl implements IMediaServerService {
122 } 127 }
123 } 128 }
124 129
125 - @Override  
126 - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback) {  
127 - return openRTPServer(mediaServerItem, streamId, null, ssrcCheck,isPlayback);  
128 - }  
129 130
130 @Override 131 @Override
131 public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck, 132 public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String presetSsrc, boolean ssrcCheck,
132 - boolean isPlayback, Integer port, Boolean onlyAuto) { 133 + boolean isPlayback, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode) {
133 if (mediaServerItem == null || mediaServerItem.getId() == null) { 134 if (mediaServerItem == null || mediaServerItem.getId() == null) {
134 logger.info("[openRTPServer] 失败, mediaServerItem == null || mediaServerItem.getId() == null"); 135 logger.info("[openRTPServer] 失败, mediaServerItem == null || mediaServerItem.getId() == null");
135 return null; 136 return null;
136 } 137 }
137 // 获取mediaServer可用的ssrc 138 // 获取mediaServer可用的ssrc
138 - String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();  
139 -  
140 - SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();  
141 - if (ssrcConfig == null) {  
142 - logger.info("media server [ {} ] ssrcConfig is null", mediaServerItem.getId());  
143 - return null; 139 + String ssrc;
  140 + if (presetSsrc != null) {
  141 + ssrc = presetSsrc;
144 }else { 142 }else {
145 - String ssrc;  
146 - if (presetSsrc != null) {  
147 - ssrc = presetSsrc; 143 + if (isPlayback) {
  144 + ssrc = ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
148 }else { 145 }else {
149 - if (isPlayback) {  
150 - ssrc = ssrcConfig.getPlayBackSsrc();  
151 - }else {  
152 - ssrc = ssrcConfig.getPlaySsrc();  
153 - } 146 + ssrc = ssrcFactory.getPlaySsrc(mediaServerItem.getId());
154 } 147 }
  148 + }
155 149
156 - if (streamId == null) {  
157 - streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();  
158 - }  
159 - int rtpServerPort;  
160 - if (mediaServerItem.isRtpEnable()) {  
161 - rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port, onlyAuto);  
162 - } else {  
163 - rtpServerPort = mediaServerItem.getRtpProxyPort();  
164 - }  
165 - redisTemplate.opsForValue().set(key, mediaServerItem);  
166 - return new SSRCInfo(rtpServerPort, ssrc, streamId); 150 + if (streamId == null) {
  151 + streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
  152 + }
  153 + int rtpServerPort;
  154 + if (mediaServerItem.isRtpEnable()) {
  155 + rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port, onlyAuto, reUsePort, tcpMode);
  156 + } else {
  157 + rtpServerPort = mediaServerItem.getRtpProxyPort();
167 } 158 }
  159 + return new SSRCInfo(rtpServerPort, ssrc, streamId);
168 } 160 }
169 161
170 @Override 162 @Override
171 - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback) { 163 + public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback, Integer port, Boolean onlyAuto) {
172 return openRTPServer(mediaServerItem, streamId, ssrc, ssrcCheck, isPlayback, null, null); 164 return openRTPServer(mediaServerItem, streamId, ssrc, ssrcCheck, isPlayback, null, null);
173 } 165 }
174 166
  167 +
175 @Override 168 @Override
176 public void closeRTPServer(MediaServerItem mediaServerItem, String streamId) { 169 public void closeRTPServer(MediaServerItem mediaServerItem, String streamId) {
177 if (mediaServerItem == null) { 170 if (mediaServerItem == null) {
@@ -181,22 +174,32 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -181,22 +174,32 @@ public class MediaServerServiceImpl implements IMediaServerService {
181 } 174 }
182 175
183 @Override 176 @Override
  177 + public void closeRTPServer(MediaServerItem mediaServerItem, String streamId, CommonCallback<Boolean> callback) {
  178 + if (mediaServerItem == null) {
  179 + callback.run(false);
  180 + return;
  181 + }
  182 + zlmrtpServerFactory.closeRtpServer(mediaServerItem, streamId, callback);
  183 + }
  184 +
  185 + @Override
184 public void closeRTPServer(String mediaServerId, String streamId) { 186 public void closeRTPServer(String mediaServerId, String streamId) {
185 MediaServerItem mediaServerItem = this.getOne(mediaServerId); 187 MediaServerItem mediaServerItem = this.getOne(mediaServerId);
186 closeRTPServer(mediaServerItem, streamId); 188 closeRTPServer(mediaServerItem, streamId);
187 } 189 }
188 190
189 @Override 191 @Override
  192 + public Boolean updateRtpServerSSRC(MediaServerItem mediaServerItem, String streamId, String ssrc) {
  193 + return zlmrtpServerFactory.updateRtpServerSSRC(mediaServerItem, streamId, ssrc);
  194 + }
  195 +
  196 + @Override
190 public void releaseSsrc(String mediaServerItemId, String ssrc) { 197 public void releaseSsrc(String mediaServerItemId, String ssrc) {
191 MediaServerItem mediaServerItem = getOne(mediaServerItemId); 198 MediaServerItem mediaServerItem = getOne(mediaServerItemId);
192 if (mediaServerItem == null || ssrc == null) { 199 if (mediaServerItem == null || ssrc == null) {
193 return; 200 return;
194 } 201 }
195 - SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();  
196 - ssrcConfig.releaseSsrc(ssrc);  
197 - mediaServerItem.setSsrcConfig(ssrcConfig);  
198 - String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();  
199 - redisTemplate.opsForValue().set(key, mediaServerItem); 202 + ssrcFactory.releaseSsrc(mediaServerItemId, ssrc);
200 } 203 }
201 204
202 /** 205 /**
@@ -204,8 +207,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -204,8 +207,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
204 */ 207 */
205 @Override 208 @Override
206 public void clearRTPServer(MediaServerItem mediaServerItem) { 209 public void clearRTPServer(MediaServerItem mediaServerItem) {
207 - mediaServerItem.setSsrcConfig(new SsrcConfig(mediaServerItem.getId(), null, sipConfig.getDomain()));  
208 - redisTemplate.opsForZSet().add(VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId(), mediaServerItem.getId(), 0); 210 + ssrcFactory.reset(mediaServerItem.getId());
209 211
210 } 212 }
211 213
@@ -215,16 +217,8 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -215,16 +217,8 @@ public class MediaServerServiceImpl implements IMediaServerService {
215 mediaServerMapper.update(mediaSerItem); 217 mediaServerMapper.update(mediaSerItem);
216 MediaServerItem mediaServerItemInRedis = getOne(mediaSerItem.getId()); 218 MediaServerItem mediaServerItemInRedis = getOne(mediaSerItem.getId());
217 MediaServerItem mediaServerItemInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId()); 219 MediaServerItem mediaServerItemInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId());
218 - if (mediaServerItemInRedis != null && mediaServerItemInRedis.getSsrcConfig() != null) {  
219 - mediaServerItemInDataBase.setSsrcConfig(mediaServerItemInRedis.getSsrcConfig());  
220 - }else {  
221 - mediaServerItemInDataBase.setSsrcConfig(  
222 - new SsrcConfig(  
223 - mediaServerItemInDataBase.getId(),  
224 - null,  
225 - sipConfig.getDomain()  
226 - )  
227 - ); 220 + if (mediaServerItemInRedis == null || ssrcFactory.hasMediaServerSSRC(mediaSerItem.getId())) {
  221 + ssrcFactory.initMediaServerSSRC(mediaServerItemInDataBase.getId(),null);
228 } 222 }
229 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItemInDataBase.getId(); 223 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItemInDataBase.getId();
230 redisTemplate.opsForValue().set(key, mediaServerItemInDataBase); 224 redisTemplate.opsForValue().set(key, mediaServerItemInDataBase);
@@ -406,14 +400,8 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -406,14 +400,8 @@ public class MediaServerServiceImpl implements IMediaServerService {
406 } 400 }
407 mediaServerMapper.update(serverItem); 401 mediaServerMapper.update(serverItem);
408 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + zlmServerConfig.getGeneralMediaServerId(); 402 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + zlmServerConfig.getGeneralMediaServerId();
409 - if (redisTemplate.opsForValue().get(key) == null) {  
410 - SsrcConfig ssrcConfig = new SsrcConfig(zlmServerConfig.getGeneralMediaServerId(), null, sipConfig.getDomain());  
411 - serverItem.setSsrcConfig(ssrcConfig);  
412 - }else {  
413 - MediaServerItem mediaServerItemInRedis = JsonUtil.redisJsonToObject(redisTemplate, key, MediaServerItem.class);  
414 - if (Objects.nonNull(mediaServerItemInRedis)) {  
415 - serverItem.setSsrcConfig(mediaServerItemInRedis.getSsrcConfig());  
416 - } 403 + if (ssrcFactory.hasMediaServerSSRC(serverItem.getId())) {
  404 + ssrcFactory.initMediaServerSSRC(zlmServerConfig.getGeneralMediaServerId(), null);
417 } 405 }
418 redisTemplate.opsForValue().set(key, serverItem); 406 redisTemplate.opsForValue().set(key, serverItem);
419 resetOnlineServerItem(serverItem); 407 resetOnlineServerItem(serverItem);
@@ -711,8 +699,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -711,8 +699,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
711 } 699 }
712 // zlm连接重试 700 // zlm连接重试
713 logger.warn("[更新ZLM 保活信息]尝试链接zml id {}", mediaServerId); 701 logger.warn("[更新ZLM 保活信息]尝试链接zml id {}", mediaServerId);
714 - SsrcConfig ssrcConfig = new SsrcConfig(mediaServerItem.getId(), null, sipConfig.getDomain());  
715 - mediaServerItem.setSsrcConfig(ssrcConfig); 702 + ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null);
716 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId(); 703 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
717 redisTemplate.opsForValue().set(key, mediaServerItem); 704 redisTemplate.opsForValue().set(key, mediaServerItem);
718 clearRTPServer(mediaServerItem); 705 clearRTPServer(mediaServerItem);
@@ -761,4 +748,5 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -761,4 +748,5 @@ public class MediaServerServiceImpl implements IMediaServerService {
761 result.setGbSend(redisCatchStorage.getGbSendCount(mediaServerItem.getId())); 748 result.setGbSend(redisCatchStorage.getGbSendCount(mediaServerItem.getId()));
762 return result; 749 return result;
763 } 750 }
  751 +
764 } 752 }
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
1 package com.genersoft.iot.vmp.service.impl; 1 package com.genersoft.iot.vmp.service.impl;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
4 -import com.genersoft.iot.vmp.common.StreamInfo; 4 +import com.genersoft.iot.vmp.common.InviteInfo;
  5 +import com.genersoft.iot.vmp.common.InviteSessionType;
5 import com.genersoft.iot.vmp.conf.DynamicTask; 6 import com.genersoft.iot.vmp.conf.DynamicTask;
6 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 8 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
8 import com.genersoft.iot.vmp.gb28181.bean.*; 9 import com.genersoft.iot.vmp.gb28181.bean.*;
9 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 10 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  11 +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
10 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 12 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 13 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
12 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 14 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
@@ -14,6 +16,7 @@ import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; @@ -14,6 +16,7 @@ import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
14 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; 16 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
15 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; 17 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
16 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 18 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  19 +import com.genersoft.iot.vmp.service.IInviteStreamService;
17 import com.genersoft.iot.vmp.service.IMediaServerService; 20 import com.genersoft.iot.vmp.service.IMediaServerService;
18 import com.genersoft.iot.vmp.service.IPlatformService; 21 import com.genersoft.iot.vmp.service.IPlatformService;
19 import com.genersoft.iot.vmp.service.IPlayService; 22 import com.genersoft.iot.vmp.service.IPlayService;
@@ -66,6 +69,9 @@ public class PlatformServiceImpl implements IPlatformService { @@ -66,6 +69,9 @@ public class PlatformServiceImpl implements IPlatformService {
66 private IRedisCatchStorage redisCatchStorage; 69 private IRedisCatchStorage redisCatchStorage;
67 70
68 @Autowired 71 @Autowired
  72 + private SSRCFactory ssrcFactory;
  73 +
  74 + @Autowired
69 private IMediaServerService mediaServerService; 75 private IMediaServerService mediaServerService;
70 76
71 @Autowired 77 @Autowired
@@ -96,6 +102,8 @@ public class PlatformServiceImpl implements IPlatformService { @@ -96,6 +102,8 @@ public class PlatformServiceImpl implements IPlatformService {
96 @Autowired 102 @Autowired
97 private IPlayService playService; 103 private IPlayService playService;
98 104
  105 + @Autowired
  106 + private IInviteStreamService inviteStreamService;
99 107
100 108
101 @Override 109 @Override
@@ -198,6 +206,7 @@ public class PlatformServiceImpl implements IPlatformService { @@ -198,6 +206,7 @@ public class PlatformServiceImpl implements IPlatformService {
198 // 保存时启用就发送注册 206 // 保存时启用就发送注册
199 // 注册成功时由程序直接调用了online方法 207 // 注册成功时由程序直接调用了online方法
200 try { 208 try {
  209 + logger.info("[国标级联] 平台注册 {}", parentPlatform.getDeviceGBId());
201 commanderForPlatform.register(parentPlatform, eventResult -> { 210 commanderForPlatform.register(parentPlatform, eventResult -> {
202 logger.info("[国标级联] {},添加向上级注册失败,请确定上级平台可用时重新保存", parentPlatform.getServerGBId()); 211 logger.info("[国标级联] {},添加向上级注册失败,请确定上级平台可用时重新保存", parentPlatform.getServerGBId());
203 }, null); 212 }, null);
@@ -349,6 +358,7 @@ public class PlatformServiceImpl implements IPlatformService { @@ -349,6 +358,7 @@ public class PlatformServiceImpl implements IPlatformService {
349 List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServer(platformId); 358 List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServer(platformId);
350 if (sendRtpItems != null && sendRtpItems.size() > 0) { 359 if (sendRtpItems != null && sendRtpItems.size() > 0) {
351 for (SendRtpItem sendRtpItem : sendRtpItems) { 360 for (SendRtpItem sendRtpItem : sendRtpItems) {
  361 + ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
352 redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), null, null); 362 redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), null, null);
353 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); 363 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
354 Map<String, Object> param = new HashMap<>(3); 364 Map<String, Object> param = new HashMap<>(3);
@@ -420,20 +430,22 @@ public class PlatformServiceImpl implements IPlatformService { @@ -420,20 +430,22 @@ public class PlatformServiceImpl implements IPlatformService {
420 logger.info("[国标级联] 语音喊话未找到可用的zlm. platform: {}", platform.getServerGBId()); 430 logger.info("[国标级联] 语音喊话未找到可用的zlm. platform: {}", platform.getServerGBId());
421 return; 431 return;
422 } 432 }
423 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(platform.getServerGBId(), channelId);  
424 - if (streamInfo != null) { 433 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, platform.getServerGBId(), channelId);
  434 +
  435 +
  436 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
425 // 如果zlm不存在这个流,则删除数据即可 437 // 如果zlm不存在这个流,则删除数据即可
426 - MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(streamInfo.getMediaServerId()); 438 + MediaServerItem mediaServerItemForStreamInfo = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
427 if (mediaServerItemForStreamInfo != null) { 439 if (mediaServerItemForStreamInfo != null) {
428 - Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItemForStreamInfo, streamInfo.getApp(), streamInfo.getStream()); 440 + Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItemForStreamInfo, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream());
429 if (!ready) { 441 if (!ready) {
430 // 错误存在于redis中的数据 442 // 错误存在于redis中的数据
431 - redisCatchStorage.stopPlay(streamInfo); 443 + inviteStreamService.removeInviteInfo(inviteInfo);
432 }else { 444 }else {
433 // 流确实尚在推流,直接回调结果 445 // 流确实尚在推流,直接回调结果
434 JSONObject json = new JSONObject(); 446 JSONObject json = new JSONObject();
435 - json.put("app", streamInfo.getApp());  
436 - json.put("stream", streamInfo.getStream()); 447 + json.put("app", inviteInfo.getStreamInfo().getApp());
  448 + json.put("stream", inviteInfo.getStreamInfo().getStream());
437 hookEvent.response(mediaServerItemForStreamInfo, json); 449 hookEvent.response(mediaServerItemForStreamInfo, json);
438 return; 450 return;
439 } 451 }
@@ -449,7 +461,11 @@ public class PlatformServiceImpl implements IPlatformService { @@ -449,7 +461,11 @@ public class PlatformServiceImpl implements IPlatformService {
449 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, ssrcCheck, false, null, true); 461 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, ssrcCheck, false, null, true);
450 if (ssrcInfo == null || ssrcInfo.getPort() < 0) { 462 if (ssrcInfo == null || ssrcInfo.getPort() < 0) {
451 logger.info("[国标级联] 发起语音喊话 开启端口监听失败, platform: {}, channel: {}", platform.getServerGBId(), channelId); 463 logger.info("[国标级联] 发起语音喊话 开启端口监听失败, platform: {}, channel: {}", platform.getServerGBId(), channelId);
452 - errorEvent.response(new SipSubscribe.EventResult(-1, "端口监听失败")); 464 + SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
  465 + eventResult.statusCode = -1;
  466 + eventResult.msg = "端口监听失败";
  467 + eventResult.type = SipSubscribe.EventResultType.failedToGetPort;
  468 + errorEvent.response(eventResult);
453 return; 469 return;
454 } 470 }
455 logger.info("[国标级联] 语音喊话,发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", 471 logger.info("[国标级联] 语音喊话,发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
@@ -458,7 +474,8 @@ public class PlatformServiceImpl implements IPlatformService { @@ -458,7 +474,8 @@ public class PlatformServiceImpl implements IPlatformService {
458 String timeOutTaskKey = UUID.randomUUID().toString(); 474 String timeOutTaskKey = UUID.randomUUID().toString();
459 dynamicTask.startDelay(timeOutTaskKey, () -> { 475 dynamicTask.startDelay(timeOutTaskKey, () -> {
460 // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况 476 // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况
461 - if (redisCatchStorage.queryPlayByDevice(platform.getServerGBId(), channelId) == null) { 477 + InviteInfo inviteInfoForBroadcast = inviteStreamService.getInviteInfo(InviteSessionType.BROADCAST, platform.getServerGBId(), channelId, null);
  478 + if (inviteInfoForBroadcast == null) {
462 logger.info("[国标级联] 发起语音喊话 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", platform.getServerGBId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc()); 479 logger.info("[国标级联] 发起语音喊话 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", platform.getServerGBId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc());
463 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 480 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
464 try { 481 try {
@@ -501,7 +518,7 @@ public class PlatformServiceImpl implements IPlatformService { @@ -501,7 +518,7 @@ public class PlatformServiceImpl implements IPlatformService {
501 if (!mediaServerItem.isRtpEnable()) { 518 if (!mediaServerItem.isRtpEnable()) {
502 logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); 519 logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
503 520
504 - if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) { 521 + if (!ssrcFactory.checkSsrc(mediaServerItem.getId(), ssrcInResponse)) {
505 // ssrc 不可用 522 // ssrc 不可用
506 // 释放ssrc 523 // 释放ssrc
507 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 524 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
1 package com.genersoft.iot.vmp.service.impl; 1 package com.genersoft.iot.vmp.service.impl;
2 2
3 -import com.alibaba.fastjson2.JSON;  
4 import com.alibaba.fastjson2.JSONArray; 3 import com.alibaba.fastjson2.JSONArray;
5 import com.alibaba.fastjson2.JSONObject; 4 import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.InviteInfo;
  6 +import com.genersoft.iot.vmp.common.InviteSessionStatus;
  7 +import com.genersoft.iot.vmp.common.InviteSessionType;
6 import com.genersoft.iot.vmp.common.StreamInfo; 8 import com.genersoft.iot.vmp.common.StreamInfo;
7 import com.genersoft.iot.vmp.conf.DynamicTask; 9 import com.genersoft.iot.vmp.conf.DynamicTask;
8 import com.genersoft.iot.vmp.conf.SipConfig; 10 import com.genersoft.iot.vmp.conf.SipConfig;
@@ -13,9 +15,9 @@ import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; @@ -13,9 +15,9 @@ import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
13 import com.genersoft.iot.vmp.gb28181.bean.*; 15 import com.genersoft.iot.vmp.gb28181.bean.*;
14 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 16 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
15 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; 17 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
  18 +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
16 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 19 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
17 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 20 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
18 -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;  
19 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; 21 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
20 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 22 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
21 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 23 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
@@ -27,11 +29,11 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; @@ -27,11 +29,11 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
27 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; 29 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
28 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; 30 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
29 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 31 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
30 -import com.genersoft.iot.vmp.service.IDeviceService;  
31 -import com.genersoft.iot.vmp.service.IMediaServerService;  
32 -import com.genersoft.iot.vmp.service.IMediaService;  
33 -import com.genersoft.iot.vmp.service.IPlayService;  
34 -import com.genersoft.iot.vmp.service.bean.*; 32 +import com.genersoft.iot.vmp.service.*;
  33 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  34 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
  35 +import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
  36 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
35 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; 37 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
36 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 38 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
37 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 39 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
@@ -39,7 +41,6 @@ import com.genersoft.iot.vmp.utils.DateUtil; @@ -39,7 +41,6 @@ import com.genersoft.iot.vmp.utils.DateUtil;
39 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; 41 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
40 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 42 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
41 import com.genersoft.iot.vmp.vmanager.bean.StreamContent; 43 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
42 -import com.genersoft.iot.vmp.vmanager.bean.WVPResult;  
43 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; 44 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
44 import gov.nist.javax.sip.message.SIPResponse; 45 import gov.nist.javax.sip.message.SIPResponse;
45 import org.slf4j.Logger; 46 import org.slf4j.Logger;
@@ -51,6 +52,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -51,6 +52,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
51 import org.springframework.stereotype.Service; 52 import org.springframework.stereotype.Service;
52 import org.springframework.util.ObjectUtils; 53 import org.springframework.util.ObjectUtils;
53 54
  55 +import javax.sdp.*;
54 import javax.sip.InvalidArgumentException; 56 import javax.sip.InvalidArgumentException;
55 import javax.sip.ResponseEvent; 57 import javax.sip.ResponseEvent;
56 import javax.sip.SipException; 58 import javax.sip.SipException;
@@ -88,6 +90,9 @@ public class PlayServiceImpl implements IPlayService { @@ -88,6 +90,9 @@ public class PlayServiceImpl implements IPlayService {
88 private ZLMRTPServerFactory zlmrtpServerFactory; 90 private ZLMRTPServerFactory zlmrtpServerFactory;
89 91
90 @Autowired 92 @Autowired
  93 + private IInviteStreamService inviteStreamService;
  94 +
  95 + @Autowired
91 private DeferredResultHolder resultHolder; 96 private DeferredResultHolder resultHolder;
92 97
93 @Autowired 98 @Autowired
@@ -132,125 +137,81 @@ public class PlayServiceImpl implements IPlayService { @@ -132,125 +137,81 @@ public class PlayServiceImpl implements IPlayService {
132 private ZlmHttpHookSubscribe hookSubscribe; 137 private ZlmHttpHookSubscribe hookSubscribe;
133 138
134 @Autowired 139 @Autowired
  140 + private SSRCFactory ssrcFactory;
  141 +
  142 + @Autowired
135 private RedisTemplate<Object, Object> redisTemplate; 143 private RedisTemplate<Object, Object> redisTemplate;
136 144
137 145
138 @Override 146 @Override
139 - public void play(MediaServerItem mediaServerItem, String deviceId, String channelId,  
140 - ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,  
141 - Runnable timeoutCallback) { 147 + public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, InviteErrorCallback<Object> callback) {
142 if (mediaServerItem == null) { 148 if (mediaServerItem == null) {
143 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm"); 149 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm");
144 } 150 }
145 - String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;  
146 -  
147 - RequestMessage msg = new RequestMessage();  
148 - msg.setKey(key);  
149 151
150 Device device = redisCatchStorage.getDevice(deviceId); 152 Device device = redisCatchStorage.getDevice(deviceId);
151 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);  
152 -  
153 - if (streamInfo != null) {  
154 - String streamId = streamInfo.getStream();  
155 - if (streamId == null) {  
156 - WVPResult wvpResult = new WVPResult();  
157 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
158 - wvpResult.setMsg("点播失败, redis缓存streamId等于null");  
159 - msg.setData(wvpResult);  
160 - resultHolder.invokeAllResult(msg);  
161 - return;  
162 - }  
163 - String mediaServerId = streamInfo.getMediaServerId();  
164 - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);  
165 -  
166 - JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);  
167 - if (rtpInfo.getInteger("code") == 0) {  
168 - if (rtpInfo.getBoolean("exist")) {  
169 - int localPort = rtpInfo.getInteger("local_port");  
170 - if (localPort == 0) {  
171 - logger.warn("[点播],点播时发现rtpServerC存在,但是尚未开始推流");  
172 - // 此时说明rtpServer已经创建但是流还没有推上来  
173 - WVPResult wvpResult = new WVPResult();  
174 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
175 - wvpResult.setMsg("点播已经在进行中,请稍候重试");  
176 - msg.setData(wvpResult);  
177 -  
178 - resultHolder.invokeAllResult(msg);  
179 - return;  
180 - } else {  
181 - WVPResult wvpResult = new WVPResult();  
182 - wvpResult.setCode(ErrorCode.SUCCESS.getCode());  
183 - wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());  
184 - wvpResult.setData(streamInfo);  
185 - msg.setData(wvpResult);  
186 - resultHolder.invokeAllResult(msg);  
187 - if (hookEvent != null) {  
188 - hookEvent.response(mediaServerItem, JSON.parseObject(JSON.toJSONString(streamInfo)));  
189 - }  
190 - }  
191 -  
192 - } else {  
193 - redisCatchStorage.stopPlay(streamInfo); 153 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  154 +
  155 + if (inviteInfo != null ) {
  156 + if (inviteInfo.getStreamInfo() == null) {
  157 + // 点播发起了但是尚未成功, 仅注册回调等待结果即可
  158 + inviteStreamService.once(InviteSessionType.PLAY, deviceId, channelId, null, callback);
  159 + return inviteInfo.getSsrcInfo();
  160 + }else {
  161 + StreamInfo streamInfo = inviteInfo.getStreamInfo();
  162 + String streamId = streamInfo.getStream();
  163 + if (streamId == null) {
  164 + callback.run(InviteErrorCode.ERROR_FOR_CATCH_DATA.getCode(), "点播失败, redis缓存streamId等于null", null);
  165 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  166 + InviteErrorCode.ERROR_FOR_CATCH_DATA.getCode(),
  167 + "点播失败, redis缓存streamId等于null",
  168 + null);
  169 + return inviteInfo.getSsrcInfo();
  170 + }
  171 + String mediaServerId = streamInfo.getMediaServerId();
  172 + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  173 +
  174 + Boolean ready = zlmrtpServerFactory.isStreamReady(mediaInfo, "rtp", streamId);
  175 + if (ready != null && ready) {
  176 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  177 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  178 + InviteErrorCode.SUCCESS.getCode(),
  179 + InviteErrorCode.SUCCESS.getMsg(),
  180 + streamInfo);
  181 + return inviteInfo.getSsrcInfo();
  182 + }else {
  183 + // 点播发起了但是尚未成功, 仅注册回调等待结果即可
  184 + inviteStreamService.once(InviteSessionType.PLAY, deviceId, channelId, null, callback);
194 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 185 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
195 - streamInfo = null; 186 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
196 } 187 }
197 - } else {  
198 - //zlm连接失败  
199 - redisCatchStorage.stopPlay(streamInfo);  
200 - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());  
201 - streamInfo = null;  
202 } 188 }
203 } 189 }
204 - if (streamInfo == null) {  
205 - String streamId = null;  
206 - if (mediaServerItem.isRtpEnable()) {  
207 - streamId = String.format("%s_%s", device.getDeviceId(), channelId);  
208 - }  
209 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);  
210 - if (ssrcInfo == null) {  
211 - WVPResult wvpResult = new WVPResult();  
212 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
213 - wvpResult.setMsg("开启收流失败");  
214 - msg.setData(wvpResult);  
215 -  
216 - resultHolder.invokeAllResult(msg);  
217 - return;  
218 - }  
219 - play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response) -> {  
220 - if (hookEvent != null) {  
221 - hookEvent.response(mediaServerItem, response);  
222 - }  
223 - }, event -> {  
224 - // sip error错误  
225 - WVPResult wvpResult = new WVPResult();  
226 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
227 - wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));  
228 - msg.setData(wvpResult);  
229 - resultHolder.invokeAllResult(msg);  
230 - if (errorEvent != null) {  
231 - errorEvent.response(event);  
232 - }  
233 - }, (code, msgStr) -> {  
234 - // invite点播超时  
235 - WVPResult wvpResult = new WVPResult();  
236 - wvpResult.setCode(ErrorCode.ERROR100.getCode());  
237 - if (code == 0) {  
238 - wvpResult.setMsg("点播超时,请稍候重试");  
239 - } else if (code == 1) {  
240 - wvpResult.setMsg("收流超时,请稍候重试");  
241 - }  
242 - msg.setData(wvpResult);  
243 - // 回复之前所有的点播请求  
244 - resultHolder.invokeAllResult(msg);  
245 - }); 190 +
  191 + String streamId = null;
  192 + if (mediaServerItem.isRtpEnable()) {
  193 + streamId = String.format("%s_%s", device.getDeviceId(), channelId);
  194 + }
  195 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false, 0, false, false, device.getStreamModeForParam());
  196 + if (ssrcInfo == null) {
  197 + callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getMsg(), null);
  198 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  199 + InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(),
  200 + InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getMsg(),
  201 + null);
  202 + return null;
246 } 203 }
  204 + // TODO 记录点播的状态
  205 + play(mediaServerItem, ssrcInfo, device, channelId, callback);
  206 + return ssrcInfo;
247 } 207 }
248 208
249 private void talk(MediaServerItem mediaServerItem, Device device, String channelId, String stream, 209 private void talk(MediaServerItem mediaServerItem, Device device, String channelId, String stream,
250 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, 210 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
251 Runnable timeoutCallback, AudioBroadcastEvent audioEvent) { 211 Runnable timeoutCallback, AudioBroadcastEvent audioEvent) {
252 212
253 - String playSsrc = mediaServerItem.getSsrcConfig().getPlaySsrc(); 213 + String playSsrc = ssrcFactory.getPlaySsrc(mediaServerItem.getId());
  214 +
254 if (playSsrc == null) { 215 if (playSsrc == null) {
255 audioEvent.call("ssrc已经用尽"); 216 audioEvent.call("ssrc已经用尽");
256 return; 217 return;
@@ -353,7 +314,7 @@ public class PlayServiceImpl implements IPlayService { @@ -353,7 +314,7 @@ public class PlayServiceImpl implements IPlayService {
353 314
354 streamSession.put(device.getDeviceId(), channelId, "talk", 315 streamSession.put(device.getDeviceId(), channelId, "talk",
355 sendRtpItem.getStream(), sendRtpItem.getSsrc(), sendRtpItem.getMediaServerId(), 316 sendRtpItem.getStream(), sendRtpItem.getSsrc(), sendRtpItem.getMediaServerId(),
356 - response, VideoStreamSessionManager.SessionType.talk); 317 + response, InviteSessionType.TALK);
357 } else { 318 } else {
358 logger.error("[语音对讲]收到的消息错误,response不是SIPResponse"); 319 logger.error("[语音对讲]收到的消息错误,response不是SIPResponse");
359 } 320 }
@@ -378,7 +339,9 @@ public class PlayServiceImpl implements IPlayService { @@ -378,7 +339,9 @@ public class PlayServiceImpl implements IPlayService {
378 mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc()); 339 mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
379 340
380 streamSession.remove(device.getDeviceId(), channelId, sendRtpItem.getStream()); 341 streamSession.remove(device.getDeviceId(), channelId, sendRtpItem.getStream());
381 - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null)); 342 + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();
  343 + eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent;
  344 + eventResult.statusCode = -1;
382 eventResult.msg = "命令发送失败"; 345 eventResult.msg = "命令发送失败";
383 errorEvent.response(eventResult); 346 errorEvent.response(eventResult);
384 } 347 }
@@ -390,24 +353,62 @@ public class PlayServiceImpl implements IPlayService { @@ -390,24 +353,62 @@ public class PlayServiceImpl implements IPlayService {
390 353
391 @Override 354 @Override
392 public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 355 public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
393 - ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,  
394 - InviteTimeOutCallback timeoutCallback) { 356 + InviteErrorCallback<Object> callback) {
  357 +
  358 + if (mediaServerItem == null || ssrcInfo == null) {
  359 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  360 + InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
  361 + null);
  362 + return;
  363 + }
  364 + logger.info("[点播开始] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  365 +
  366 + //端口获取失败的ssrcInfo 没有必要发送点播指令
  367 + if (ssrcInfo.getPort() <= 0) {
  368 + logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo);
  369 + // 释放ssrc
  370 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  371 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
395 372
396 - logger.info("[点播开始] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); 373 + callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null);
  374 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  375 + InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null);
  376 + return;
  377 + }
  378 +
  379 + // 初始化redis中的invite消息状态
  380 + InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  381 + mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY,
  382 + InviteSessionStatus.ready);
  383 + inviteStreamService.updateInviteInfo(inviteInfo);
397 // 超时处理 384 // 超时处理
398 String timeOutTaskKey = UUID.randomUUID().toString(); 385 String timeOutTaskKey = UUID.randomUUID().toString();
399 dynamicTask.startDelay(timeOutTaskKey, () -> { 386 dynamicTask.startDelay(timeOutTaskKey, () -> {
400 // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况 387 // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况
401 - if (redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId) == null) { 388 + InviteInfo inviteInfoForTimeOut = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
  389 + if (inviteInfoForTimeOut == null || inviteInfoForTimeOut.getStreamInfo() == null) {
402 logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc()); 390 logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc());
403 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 391 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
  392 +// InviteInfo inviteInfoForTimeout = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.play, device.getDeviceId(), channelId);
  393 +// if (inviteInfoForTimeout == null) {
  394 +// return;
  395 +// }
  396 +// if (InviteSessionStatus.ok == inviteInfoForTimeout.getStatus() ) {
  397 +// // TODO 发送bye
  398 +// }else {
  399 +// // TODO 发送cancel
  400 +// }
  401 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
  402 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  403 + InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
  404 +
  405 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
404 try { 406 try {
405 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); 407 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null);
406 } catch (InvalidArgumentException | ParseException | SipException | 408 } catch (InvalidArgumentException | ParseException | SipException |
407 SsrcTransactionNotFoundException e) { 409 SsrcTransactionNotFoundException e) {
408 logger.error("[点播超时], 发送BYE失败 {}", e.getMessage()); 410 logger.error("[点播超时], 发送BYE失败 {}", e.getMessage());
409 } finally { 411 } finally {
410 - timeoutCallback.run(1, "收流超时");  
411 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 412 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
412 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); 413 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
413 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 414 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
@@ -418,28 +419,26 @@ public class PlayServiceImpl implements IPlayService { @@ -418,28 +419,26 @@ public class PlayServiceImpl implements IPlayService {
418 } 419 }
419 } 420 }
420 }, userSetting.getPlayTimeout()); 421 }, userSetting.getPlayTimeout());
421 - //端口获取失败的ssrcInfo 没有必要发送点播指令  
422 - if (ssrcInfo.getPort() <= 0) {  
423 - logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo);  
424 - dynamicTask.stop(timeOutTaskKey);  
425 - // 释放ssrc  
426 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
427 - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());  
428 422
429 - RequestMessage msg = new RequestMessage();  
430 - msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + device.getDeviceId() + channelId);  
431 - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "点播端口分配异常"));  
432 - resultHolder.invokeAllResult(msg);  
433 - return;  
434 - }  
435 try { 423 try {
436 cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { 424 cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
437 logger.info("收到订阅消息: " + response.toJSONString()); 425 logger.info("收到订阅消息: " + response.toJSONString());
438 dynamicTask.stop(timeOutTaskKey); 426 dynamicTask.stop(timeOutTaskKey);
439 -  
440 // hook响应 427 // hook响应
441 - onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId);  
442 - hookEvent.response(mediaServerItemInuse, response); 428 + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId);
  429 + if (streamInfo == null){
  430 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  431 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  432 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  433 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  434 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  435 + return;
  436 + }
  437 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  438 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  439 + InviteErrorCode.SUCCESS.getCode(),
  440 + InviteErrorCode.SUCCESS.getMsg(),
  441 + streamInfo);
443 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); 442 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
444 String streamUrl; 443 String streamUrl;
445 if (mediaServerItemInuse.getRtspPort() != 0) { 444 if (mediaServerItemInuse.getRtspPort() != 0) {
@@ -454,6 +453,8 @@ public class PlayServiceImpl implements IPlayService { @@ -454,6 +453,8 @@ public class PlayServiceImpl implements IPlayService {
454 zlmresTfulUtils.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName); 453 zlmresTfulUtils.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName);
455 454
456 }, (event) -> { 455 }, (event) -> {
  456 + inviteInfo.setStatus(InviteSessionStatus.ok);
  457 +
457 ResponseEvent responseEvent = (ResponseEvent) event.event; 458 ResponseEvent responseEvent = (ResponseEvent) event.event;
458 String contentString = new String(responseEvent.getResponse().getRawContent()); 459 String contentString = new String(responseEvent.getResponse().getRawContent());
459 // 获取ssrc 460 // 获取ssrc
@@ -464,44 +465,124 @@ public class PlayServiceImpl implements IPlayService { @@ -464,44 +465,124 @@ public class PlayServiceImpl implements IPlayService {
464 String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim(); 465 String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim();
465 // 查询到ssrc不一致且开启了ssrc校验则需要针对处理 466 // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
466 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { 467 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  468 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  469 + String substring = contentString.substring(0, contentString.indexOf("y="));
  470 + try {
  471 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  472 + int port = -1;
  473 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  474 + for (Object description : mediaDescriptions) {
  475 + MediaDescription mediaDescription = (MediaDescription) description;
  476 + Media media = mediaDescription.getMedia();
  477 +
  478 + Vector mediaFormats = media.getMediaFormats(false);
  479 + if (mediaFormats.contains("96")) {
  480 + port = media.getMediaPort();
  481 + break;
  482 + }
  483 + }
  484 + logger.info("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  485 + JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
  486 + logger.info("[点播-TCP主动连接对方] 结果: {}", jsonObject);
  487 + } catch (SdpException e) {
  488 + logger.error("[点播-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
  489 + dynamicTask.stop(timeOutTaskKey);
  490 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
  491 + // 释放ssrc
  492 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  493 +
  494 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  495 +
  496 + callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  497 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  498 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  499 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  500 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  501 + }
  502 + }
467 return; 503 return;
468 } 504 }
469 logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse); 505 logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
470 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { 506 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
471 logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); 507 logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
472 -  
473 - if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) { 508 + if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
474 // ssrc 不可用 509 // ssrc 不可用
  510 + logger.info("[点播消息] SSRC修正时发现ssrc不可使用 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
475 // 释放ssrc 511 // 释放ssrc
476 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 512 + ssrcFactory.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
477 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 513 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
478 - event.msg = "下级自定义了ssrc,但是此ssrc不可用";  
479 - event.statusCode = 400;  
480 - errorEvent.response(event); 514 +
  515 + callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  516 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  517 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  518 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  519 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  520 +
481 return; 521 return;
482 } 522 }
483 -  
484 - // 单端口模式streamId也有变化,需要重新设置监听 523 + // 单端口模式streamId也有变化,重新设置监听即可
485 if (!mediaServerItem.isRtpEnable()) { 524 if (!mediaServerItem.isRtpEnable()) {
486 // 添加订阅 525 // 添加订阅
487 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); 526 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
488 subscribe.removeSubscribe(hookSubscribe); 527 subscribe.removeSubscribe(hookSubscribe);
489 - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); 528 + String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
  529 + hookSubscribe.getContent().put("stream", stream);
  530 + inviteInfo.setStream(stream);
490 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> { 531 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
491 logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); 532 logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
492 dynamicTask.stop(timeOutTaskKey); 533 dynamicTask.stop(timeOutTaskKey);
493 // hook响应 534 // hook响应
494 - onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId);  
495 - hookEvent.response(mediaServerItemInUse, response); 535 + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId);
  536 + if (streamInfo == null){
  537 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  538 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  539 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  540 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  541 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  542 + return;
  543 + }
  544 + callback.run(InviteErrorCode.SUCCESS.getCode(),
  545 + InviteErrorCode.SUCCESS.getMsg(), null);
  546 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  547 + InviteErrorCode.SUCCESS.getCode(),
  548 + InviteErrorCode.SUCCESS.getMsg(),
  549 + streamInfo);
496 }); 550 });
  551 + return;
497 } 552 }
498 - // 关闭rtp server  
499 - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());  
500 - // 重新开启ssrc server  
501 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, ssrcInfo.getPort(), false);  
502 553
  554 + // 更新ssrc
  555 + Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
  556 + if (!result) {
  557 + try {
  558 + logger.warn("[点播] 更新ssrc失败,停止点播 {}/{}", device.getDeviceId(), channelId);
  559 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  560 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  561 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
  562 + }
  563 +
  564 + dynamicTask.stop(timeOutTaskKey);
  565 + // 释放ssrc
  566 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  567 +
  568 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  569 +
  570 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  571 + "下级自定义了ssrc,重新设置收流信息失败", null);
  572 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  573 + InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  574 + "下级自定义了ssrc,重新设置收流信息失败", null);
  575 +
  576 + }else {
  577 + ssrcInfo.setSsrc(ssrcInResponse);
  578 + inviteInfo.setSsrcInfo(ssrcInfo);
  579 + inviteInfo.setStream(ssrcInfo.getStream());
  580 + }
  581 + }else {
  582 + logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
503 } 583 }
504 } 584 }
  585 + inviteStreamService.updateInviteInfo(inviteInfo);
505 }, (event) -> { 586 }, (event) -> {
506 dynamicTask.stop(timeOutTaskKey); 587 dynamicTask.stop(timeOutTaskKey);
507 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); 588 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
@@ -509,7 +590,14 @@ public class PlayServiceImpl implements IPlayService { @@ -509,7 +590,14 @@ public class PlayServiceImpl implements IPlayService {
509 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 590 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
510 591
511 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 592 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
512 - errorEvent.response(event); 593 +
  594 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(),
  595 + String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null);
  596 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  597 + InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  598 + String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null);
  599 +
  600 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
513 }); 601 });
514 } catch (InvalidArgumentException | SipException | ParseException e) { 602 } catch (InvalidArgumentException | SipException | ParseException e) {
515 603
@@ -520,63 +608,58 @@ public class PlayServiceImpl implements IPlayService { @@ -520,63 +608,58 @@ public class PlayServiceImpl implements IPlayService {
520 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 608 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
521 609
522 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 610 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
523 - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null));  
524 - eventResult.msg = "命令发送失败";  
525 - errorEvent.response(eventResult); 611 +
  612 + callback.run(InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
  613 + InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
  614 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  615 + InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
  616 + InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
  617 +
  618 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
526 } 619 }
527 } 620 }
528 621
529 @Override 622 @Override
530 - public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId) { 623 + public StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId) {
531 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); 624 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
532 - RequestMessage msg = new RequestMessage();  
533 - msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId);  
534 if (streamInfo != null) { 625 if (streamInfo != null) {
535 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); 626 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
536 if (deviceChannel != null) { 627 if (deviceChannel != null) {
537 deviceChannel.setStreamId(streamInfo.getStream()); 628 deviceChannel.setStreamId(streamInfo.getStream());
538 storager.startPlay(deviceId, channelId, streamInfo.getStream()); 629 storager.startPlay(deviceId, channelId, streamInfo.getStream());
539 } 630 }
540 - redisCatchStorage.startPlay(streamInfo);  
541 -  
542 - WVPResult wvpResult = new WVPResult();  
543 - wvpResult.setCode(ErrorCode.SUCCESS.getCode());  
544 - wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());  
545 - wvpResult.setData(streamInfo);  
546 -  
547 - msg.setData(wvpResult);  
548 - resultHolder.invokeAllResult(msg);  
549 -  
550 - } else {  
551 - logger.warn("设备预览API调用失败!");  
552 - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "设备预览API调用失败!"));  
553 - resultHolder.invokeAllResult(msg); 631 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  632 + if (inviteInfo != null) {
  633 + inviteInfo.setStatus(InviteSessionStatus.ok);
  634 + inviteInfo.setStreamInfo(streamInfo);
  635 + inviteStreamService.updateInviteInfo(inviteInfo);
  636 + }
554 } 637 }
  638 + return streamInfo;
  639 +
555 } 640 }
556 641
557 - private void onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, PlayBackCallback playBackCallback) { 642 + private StreamInfo onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String startTime, String endTime) {
558 643
559 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); 644 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
560 - PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>();  
561 if (streamInfo != null) { 645 if (streamInfo != null) {
  646 + streamInfo.setStartTime(startTime);
  647 + streamInfo.setEndTime(endTime);
562 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); 648 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
563 if (deviceChannel != null) { 649 if (deviceChannel != null) {
564 deviceChannel.setStreamId(streamInfo.getStream()); 650 deviceChannel.setStreamId(streamInfo.getStream());
565 storager.startPlay(deviceId, channelId, streamInfo.getStream()); 651 storager.startPlay(deviceId, channelId, streamInfo.getStream());
566 } 652 }
567 - redisCatchStorage.startPlay(streamInfo); 653 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, deviceId, channelId);
  654 + if (inviteInfo != null) {
  655 + inviteInfo.setStatus(InviteSessionStatus.ok);
568 656
  657 + inviteInfo.setStreamInfo(streamInfo);
  658 + inviteStreamService.updateInviteInfo(inviteInfo);
  659 + }
569 660
570 - playBackResult.setCode(ErrorCode.SUCCESS.getCode());  
571 - playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());  
572 - playBackResult.setData(streamInfo);  
573 - playBackCallback.call(playBackResult);  
574 - } else {  
575 - logger.warn("录像回放调用失败!");  
576 - playBackResult.setCode(ErrorCode.ERROR100.getCode());  
577 - playBackResult.setMsg("录像回放调用失败!");  
578 - playBackCallback.call(playBackResult);  
579 } 661 }
  662 + return streamInfo;
580 } 663 }
581 664
582 @Override 665 @Override
@@ -615,24 +698,24 @@ public class PlayServiceImpl implements IPlayService { @@ -615,24 +698,24 @@ public class PlayServiceImpl implements IPlayService {
615 698
616 @Override 699 @Override
617 public void playBack(String deviceId, String channelId, String startTime, 700 public void playBack(String deviceId, String channelId, String startTime,
618 - String endTime, InviteStreamCallback inviteStreamCallback,  
619 - PlayBackCallback callback) { 701 + String endTime, InviteErrorCallback<Object> callback) {
620 Device device = storager.queryVideoDevice(deviceId); 702 Device device = storager.queryVideoDevice(deviceId);
621 if (device == null) { 703 if (device == null) {
622 return; 704 return;
623 } 705 }
624 MediaServerItem newMediaServerItem = getNewMediaServerItem(device); 706 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
625 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, device.isSsrcCheck(), true);  
626 -  
627 - playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback); 707 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false,false, device.getStreamModeForParam());
  708 + playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, callback);
628 } 709 }
629 710
630 @Override 711 @Override
631 public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, 712 public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
632 - String deviceId, String channelId, String startTime,  
633 - String endTime, InviteStreamCallback infoCallBack,  
634 - PlayBackCallback playBackCallback) { 713 + String deviceId, String channelId, String startTime,
  714 + String endTime, InviteErrorCallback<Object> callback) {
635 if (mediaServerItem == null || ssrcInfo == null) { 715 if (mediaServerItem == null || ssrcInfo == null) {
  716 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  717 + InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
  718 + null);
636 return; 719 return;
637 } 720 }
638 721
@@ -640,115 +723,176 @@ public class PlayServiceImpl implements IPlayService { @@ -640,115 +723,176 @@ public class PlayServiceImpl implements IPlayService {
640 if (device == null) { 723 if (device == null) {
641 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在"); 724 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在");
642 } 725 }
643 -  
644 - PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>(); 726 + logger.info("[录像回放] deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
  727 + device.getDeviceId(), channelId, startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(),
  728 + ssrcInfo.getSsrc(), device.isSsrcCheck());
  729 + // 初始化redis中的invite消息状态
  730 + InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  731 + mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK,
  732 + InviteSessionStatus.ready);
  733 + inviteStreamService.updateInviteInfo(inviteInfo);
645 String playBackTimeOutTaskKey = UUID.randomUUID().toString(); 734 String playBackTimeOutTaskKey = UUID.randomUUID().toString();
646 dynamicTask.startDelay(playBackTimeOutTaskKey, () -> { 735 dynamicTask.startDelay(playBackTimeOutTaskKey, () -> {
647 - logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));  
648 - playBackResult.setCode(ErrorCode.ERROR100.getCode());  
649 - playBackResult.setMsg("回放超时"); 736 + logger.warn("[录像回放] 超时,deviceId:{} ,channelId:{}", deviceId, channelId);
  737 + inviteStreamService.removeInviteInfo(inviteInfo);
  738 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null);
650 739
651 try { 740 try {
652 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); 741 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null);
653 } catch (InvalidArgumentException | ParseException | SipException e) { 742 } catch (InvalidArgumentException | ParseException | SipException e) {
654 - logger.error("[录像流]回放超时 发送BYE失败 {}", e.getMessage()); 743 + logger.error("[录像回放] 超时 发送BYE失败 {}", e.getMessage());
655 } catch (SsrcTransactionNotFoundException e) { 744 } catch (SsrcTransactionNotFoundException e) {
656 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 745 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
657 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 746 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
658 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); 747 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
659 streamSession.remove(deviceId, channelId, ssrcInfo.getStream()); 748 streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
660 } 749 }
661 - // 回复之前所有的点播请求  
662 - playBackCallback.call(playBackResult);  
663 }, userSetting.getPlayTimeout()); 750 }, userSetting.getPlayTimeout());
664 751
665 SipSubscribe.Event errorEvent = event -> { 752 SipSubscribe.Event errorEvent = event -> {
  753 + logger.info("[录像回放] 失败,{} {}", event.statusCode, event.msg);
666 dynamicTask.stop(playBackTimeOutTaskKey); 754 dynamicTask.stop(playBackTimeOutTaskKey);
667 - playBackResult.setCode(ErrorCode.ERROR100.getCode());  
668 - playBackResult.setMsg(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));  
669 - playBackResult.setEvent(event);  
670 - playBackCallback.call(playBackResult); 755 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(),
  756 + String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg), null);
  757 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  758 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
671 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 759 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  760 + inviteStreamService.removeInviteInfo(inviteInfo);
672 }; 761 };
673 762
674 - InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {  
675 - logger.info("收到回放订阅消息: " + inviteStreamInfo.getResponse().toJSONString()); 763 + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> {
  764 + logger.info("收到回放订阅消息: " + jsonObject);
676 dynamicTask.stop(playBackTimeOutTaskKey); 765 dynamicTask.stop(playBackTimeOutTaskKey);
677 - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); 766 + StreamInfo streamInfo = onPublishHandlerForPlayback(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime);
678 if (streamInfo == null) { 767 if (streamInfo == null) {
679 logger.warn("设备回放API调用失败!"); 768 logger.warn("设备回放API调用失败!");
680 - playBackResult.setCode(ErrorCode.ERROR100.getCode());  
681 - playBackResult.setMsg("设备回放API调用失败!");  
682 - playBackCallback.call(playBackResult); 769 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  770 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
683 return; 771 return;
684 } 772 }
685 - redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());  
686 - playBackResult.setCode(ErrorCode.SUCCESS.getCode());  
687 - playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());  
688 - playBackResult.setData(streamInfo);  
689 - playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());  
690 - playBackResult.setResponse(inviteStreamInfo.getResponse());  
691 - playBackCallback.call(playBackResult); 773 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  774 + logger.info("[录像回放] 成功 deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}", device.getDeviceId(), channelId, startTime, endTime);
692 }; 775 };
693 776
694 try { 777 try {
695 - cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack, 778 + cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime,
696 hookEvent, eventResult -> { 779 hookEvent, eventResult -> {
697 - if (eventResult.type == SipSubscribe.EventResultType.response) {  
698 - ResponseEvent responseEvent = (ResponseEvent) eventResult.event;  
699 - String contentString = new String(responseEvent.getResponse().getRawContent());  
700 - // 获取ssrc  
701 - int ssrcIndex = contentString.indexOf("y=");  
702 - // 检查是否有y字段  
703 - if (ssrcIndex >= 0) {  
704 - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容  
705 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
706 - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理  
707 - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {  
708 - return;  
709 - }  
710 - logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);  
711 - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {  
712 - logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);  
713 -  
714 - if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {  
715 - // ssrc 不可用 780 + inviteInfo.setStatus(InviteSessionStatus.ok);
  781 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
  782 + String contentString = new String(responseEvent.getResponse().getRawContent());
  783 + // 获取ssrc
  784 + int ssrcIndex = contentString.indexOf("y=");
  785 + // 检查是否有y字段
  786 + if (ssrcIndex >= 0) {
  787 + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  788 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  789 + // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  790 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  791 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  792 + String substring = contentString.substring(0, contentString.indexOf("y="));
  793 + try {
  794 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  795 + int port = -1;
  796 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  797 + for (Object description : mediaDescriptions) {
  798 + MediaDescription mediaDescription = (MediaDescription) description;
  799 + Media media = mediaDescription.getMedia();
  800 +
  801 + Vector mediaFormats = media.getMediaFormats(false);
  802 + if (mediaFormats.contains("96")) {
  803 + port = media.getMediaPort();
  804 + break;
  805 + }
  806 + }
  807 + logger.info("[录像回放-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  808 + JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
  809 + logger.info("[录像回放-TCP主动连接对方] 结果: {}", jsonObject);
  810 + } catch (SdpException e) {
  811 + logger.error("[录像回放-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
  812 + dynamicTask.stop(playBackTimeOutTaskKey);
  813 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
716 // 释放ssrc 814 // 释放ssrc
717 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 815 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  816 +
718 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 817 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
719 - eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用";  
720 - eventResult.statusCode = 400;  
721 - errorEvent.response(eventResult);  
722 - return; 818 +
  819 + callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  820 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  821 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  822 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  823 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
723 } 824 }
  825 + }
  826 + return;
  827 + }
  828 + logger.info("[录像回放] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  829 + if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
  830 + logger.info("[录像回放] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  831 +
  832 + if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
  833 + // ssrc 不可用
  834 + logger.info("[录像回放] SSRC修正时发现ssrc不可使用 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  835 + // 释放ssrc
  836 + dynamicTask.stop(playBackTimeOutTaskKey);
  837 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  838 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  839 + callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  840 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  841 + return;
  842 + }
  843 +
  844 + // 单端口模式streamId也有变化,需要重新设置监听
  845 + if (!mediaServerItem.isRtpEnable()) {
  846 + // 添加订阅
  847 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  848 + subscribe.removeSubscribe(hookSubscribe);
  849 + String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
  850 + hookSubscribe.getContent().put("stream", stream);
  851 + inviteInfo.setStream(stream);
  852 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
  853 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  854 + dynamicTask.stop(playBackTimeOutTaskKey);
  855 + // hook响应
  856 + hookEvent.response(mediaServerItemInUse, response);
  857 + });
  858 + }
  859 + // 更新ssrc
  860 + Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
  861 + if (!result) {
  862 + try {
  863 + logger.warn("[录像回放] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);
  864 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  865 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  866 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
724 867
725 - // 单端口模式streamId也有变化,需要重新设置监听  
726 - if (!mediaServerItem.isRtpEnable()) {  
727 - // 添加订阅  
728 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
729 - subscribe.removeSubscribe(hookSubscribe);  
730 - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());  
731 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {  
732 - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());  
733 - dynamicTask.stop(playBackTimeOutTaskKey);  
734 - // hook响应  
735 - onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, playBackCallback);  
736 - hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));  
737 - });  
738 } 868 }
739 - // 关闭rtp server  
740 - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());  
741 - // 重新开启ssrc server  
742 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), false); 869 +
  870 + dynamicTask.stop(playBackTimeOutTaskKey);
  871 + // 释放ssrc
  872 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  873 +
  874 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  875 +
  876 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  877 + "下级自定义了ssrc,重新设置收流信息失败", null);
  878 +
  879 + }else {
  880 + ssrcInfo.setSsrc(ssrcInResponse);
  881 + inviteInfo.setSsrcInfo(ssrcInfo);
  882 + inviteInfo.setStream(ssrcInfo.getStream());
743 } 883 }
  884 + }else {
  885 + logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
744 } 886 }
745 } 887 }
746 - 888 + inviteStreamService.updateInviteInfo(inviteInfo);
747 }, errorEvent); 889 }, errorEvent);
748 } catch (InvalidArgumentException | SipException | ParseException e) { 890 } catch (InvalidArgumentException | SipException | ParseException e) {
749 logger.error("[命令发送失败] 回放: {}", e.getMessage()); 891 logger.error("[命令发送失败] 回放: {}", e.getMessage());
750 892
751 - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null)); 893 + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();
  894 + eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent;
  895 + eventResult.statusCode = -1;
752 eventResult.msg = "命令发送失败"; 896 eventResult.msg = "命令发送失败";
753 errorEvent.response(eventResult); 897 errorEvent.response(eventResult);
754 } 898 }
@@ -756,43 +900,50 @@ public class PlayServiceImpl implements IPlayService { @@ -756,43 +900,50 @@ public class PlayServiceImpl implements IPlayService {
756 900
757 901
758 @Override 902 @Override
759 - public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback) { 903 + public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) {
760 Device device = storager.queryVideoDevice(deviceId); 904 Device device = storager.queryVideoDevice(deviceId);
761 if (device == null) { 905 if (device == null) {
762 return; 906 return;
763 } 907 }
764 MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device); 908 MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device);
765 if (newMediaServerItem == null) { 909 if (newMediaServerItem == null) {
766 - PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();  
767 - downloadResult.setCode(ErrorCode.ERROR100.getCode());  
768 - downloadResult.setMsg("未找到assist服务");  
769 - playBackCallback.call(downloadResult); 910 + callback.run(InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getCode(),
  911 + InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getMsg(),
  912 + null);
770 return; 913 return;
771 } 914 }
772 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, device.isSsrcCheck(), true);  
773 -  
774 - download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, infoCallBack, playBackCallback); 915 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false,false, device.getStreamModeForParam());
  916 + download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, callback);
775 } 917 }
776 918
777 919
778 @Override 920 @Override
779 - public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) { 921 + public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) {
780 if (mediaServerItem == null || ssrcInfo == null) { 922 if (mediaServerItem == null || ssrcInfo == null) {
  923 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  924 + InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
  925 + null);
781 return; 926 return;
782 } 927 }
783 -  
784 Device device = storager.queryVideoDevice(deviceId); 928 Device device = storager.queryVideoDevice(deviceId);
785 if (device == null) { 929 if (device == null) {
786 - throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "不存在"); 930 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  931 + "设备:" + deviceId + "不存在",
  932 + null);
  933 + return;
787 } 934 }
788 - PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();  
789 - 935 + logger.info("[录像下载] deviceId: {}, channelId: {}, 下载速度:{}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, downloadSpeed, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  936 + // 初始化redis中的invite消息状态
  937 + InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  938 + mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD,
  939 + InviteSessionStatus.ready);
  940 + inviteStreamService.updateInviteInfo(inviteInfo);
790 String downLoadTimeOutTaskKey = UUID.randomUUID().toString(); 941 String downLoadTimeOutTaskKey = UUID.randomUUID().toString();
791 dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> { 942 dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> {
792 logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId)); 943 logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
793 - downloadResult.setCode(ErrorCode.ERROR100.getCode());  
794 - downloadResult.setMsg("录像下载请求超时");  
795 - hookCallBack.call(downloadResult); 944 + inviteStreamService.removeInviteInfo(inviteInfo);
  945 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(),
  946 + InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null);
796 947
797 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 948 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
798 try { 949 try {
@@ -808,85 +959,137 @@ public class PlayServiceImpl implements IPlayService { @@ -808,85 +959,137 @@ public class PlayServiceImpl implements IPlayService {
808 959
809 SipSubscribe.Event errorEvent = event -> { 960 SipSubscribe.Event errorEvent = event -> {
810 dynamicTask.stop(downLoadTimeOutTaskKey); 961 dynamicTask.stop(downLoadTimeOutTaskKey);
811 - downloadResult.setCode(ErrorCode.ERROR100.getCode());  
812 - downloadResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg));  
813 - downloadResult.setEvent(event);  
814 - hookCallBack.call(downloadResult); 962 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(),
  963 + String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg), null);
815 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 964 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  965 + inviteStreamService.removeInviteInfo(inviteInfo);
816 }; 966 };
817 - InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {  
818 - logger.info("收到订阅消息: " + inviteStreamInfo.getCallId()); 967 + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> {
  968 + logger.info("[录像下载]收到订阅消息: " + jsonObject);
819 dynamicTask.stop(downLoadTimeOutTaskKey); 969 dynamicTask.stop(downLoadTimeOutTaskKey);
820 - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);  
821 - streamInfo.setStartTime(startTime);  
822 - streamInfo.setEndTime(endTime);  
823 - redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());  
824 - downloadResult.setCode(ErrorCode.SUCCESS.getCode());  
825 - downloadResult.setMsg(ErrorCode.SUCCESS.getMsg());  
826 - downloadResult.setData(streamInfo);  
827 - downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());  
828 - downloadResult.setResponse(inviteStreamInfo.getResponse());  
829 - hookCallBack.call(downloadResult); 970 + StreamInfo streamInfo = onPublishHandlerForDownload(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime);
  971 + if (streamInfo == null) {
  972 + logger.warn("[录像下载] 获取流地址信息失败");
  973 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  974 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  975 + return;
  976 + }
  977 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  978 + logger.info("[录像下载] 调用成功 deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}", device.getDeviceId(), channelId, startTime, endTime);
830 }; 979 };
831 try { 980 try {
832 - cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack,  
833 - hookEvent, errorEvent, eventResult ->  
834 - {  
835 - if (eventResult.type == SipSubscribe.EventResultType.response) {  
836 - ResponseEvent responseEvent = (ResponseEvent) eventResult.event;  
837 - String contentString = new String(responseEvent.getResponse().getRawContent());  
838 - // 获取ssrc  
839 - int ssrcIndex = contentString.indexOf("y=");  
840 - // 检查是否有y字段  
841 - if (ssrcIndex >= 0) {  
842 - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容  
843 - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
844 - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理  
845 - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {  
846 - return;  
847 - }  
848 - logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);  
849 - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {  
850 - logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);  
851 -  
852 - if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {  
853 - // ssrc 不可用 981 + cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed,
  982 + hookEvent, errorEvent, eventResult ->{
  983 + inviteInfo.setStatus(InviteSessionStatus.ok);
  984 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
  985 + String contentString = new String(responseEvent.getResponse().getRawContent());
  986 + // 获取ssrc
  987 + int ssrcIndex = contentString.indexOf("y=");
  988 + // 检查是否有y字段
  989 + if (ssrcIndex >= 0) {
  990 + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  991 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  992 + // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  993 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  994 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  995 + String substring = contentString.substring(0, contentString.indexOf("y="));
  996 + try {
  997 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  998 + int port = -1;
  999 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  1000 + for (Object description : mediaDescriptions) {
  1001 + MediaDescription mediaDescription = (MediaDescription) description;
  1002 + Media media = mediaDescription.getMedia();
  1003 +
  1004 + Vector mediaFormats = media.getMediaFormats(false);
  1005 + if (mediaFormats.contains("96")) {
  1006 + port = media.getMediaPort();
  1007 + break;
  1008 + }
  1009 + }
  1010 + logger.info("[录像下载-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  1011 + JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
  1012 + logger.info("[录像下载-TCP主动连接对方] 结果: {}", jsonObject);
  1013 + } catch (SdpException e) {
  1014 + logger.error("[录像下载-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
  1015 + dynamicTask.stop(downLoadTimeOutTaskKey);
  1016 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
854 // 释放ssrc 1017 // 释放ssrc
855 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 1018 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  1019 +
856 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 1020 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
857 - eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用";  
858 - eventResult.statusCode = 400;  
859 - errorEvent.response(eventResult);  
860 - return; 1021 +
  1022 + callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  1023 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  1024 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  1025 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  1026 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
861 } 1027 }
  1028 + }
  1029 + return;
  1030 + }
  1031 + logger.info("[录像下载] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  1032 + if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
  1033 + logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  1034 +
  1035 + if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
  1036 + // ssrc 不可用
  1037 + // 释放ssrc
  1038 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  1039 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  1040 + callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  1041 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  1042 + return;
  1043 + }
  1044 +
  1045 + // 单端口模式streamId也有变化,需要重新设置监听
  1046 + if (!mediaServerItem.isRtpEnable()) {
  1047 + // 添加订阅
  1048 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  1049 + subscribe.removeSubscribe(hookSubscribe);
  1050 + hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
  1051 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
  1052 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  1053 + dynamicTask.stop(downLoadTimeOutTaskKey);
  1054 + hookEvent.response(mediaServerItemInUse, response);
  1055 + });
  1056 + }
862 1057
863 - // 单端口模式streamId也有变化,需要重新设置监听  
864 - if (!mediaServerItem.isRtpEnable()) {  
865 - // 添加订阅  
866 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
867 - subscribe.removeSubscribe(hookSubscribe);  
868 - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());  
869 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {  
870 - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());  
871 - dynamicTask.stop(downLoadTimeOutTaskKey);  
872 - // hook响应  
873 - onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, hookCallBack);  
874 - hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));  
875 - }); 1058 + // 更新ssrc
  1059 + Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
  1060 + if (!result) {
  1061 + try {
  1062 + logger.warn("[录像下载] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);
  1063 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  1064 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  1065 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
876 } 1066 }
877 - // 关闭rtp server  
878 - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());  
879 - // 重新开启ssrc server  
880 - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), false); 1067 +
  1068 + dynamicTask.stop(downLoadTimeOutTaskKey);
  1069 + // 释放ssrc
  1070 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  1071 +
  1072 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  1073 +
  1074 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  1075 + "下级自定义了ssrc,重新设置收流信息失败", null);
  1076 +
  1077 + }else {
  1078 + ssrcInfo.setSsrc(ssrcInResponse);
  1079 + inviteInfo.setSsrcInfo(ssrcInfo);
  1080 + inviteInfo.setStream(ssrcInfo.getStream());
881 } 1081 }
  1082 + }else {
  1083 + logger.info("[录像下载] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
882 } 1084 }
883 } 1085 }
884 -  
885 }); 1086 });
886 } catch (InvalidArgumentException | SipException | ParseException e) { 1087 } catch (InvalidArgumentException | SipException | ParseException e) {
887 logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); 1088 logger.error("[命令发送失败] 录像下载: {}", e.getMessage());
888 1089
889 - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null)); 1090 + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();
  1091 + eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent;
  1092 + eventResult.statusCode = -1;
890 eventResult.msg = "命令发送失败"; 1093 eventResult.msg = "命令发送失败";
891 errorEvent.response(eventResult); 1094 errorEvent.response(eventResult);
892 } 1095 }
@@ -894,21 +1097,22 @@ public class PlayServiceImpl implements IPlayService { @@ -894,21 +1097,22 @@ public class PlayServiceImpl implements IPlayService {
894 1097
895 @Override 1098 @Override
896 public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) { 1099 public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) {
897 - StreamInfo streamInfo = redisCatchStorage.queryDownload(deviceId, channelId, stream, null);  
898 - if (streamInfo != null) {  
899 - if (streamInfo.getProgress() == 1) {  
900 - return streamInfo; 1100 + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream);
  1101 +
  1102 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  1103 + if (inviteInfo.getStreamInfo().getProgress() == 1) {
  1104 + return inviteInfo.getStreamInfo();
901 } 1105 }
902 1106
903 // 获取当前已下载时长 1107 // 获取当前已下载时长
904 - String mediaServerId = streamInfo.getMediaServerId(); 1108 + String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId();
905 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); 1109 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
906 if (mediaServerItem == null) { 1110 if (mediaServerItem == null) {
907 logger.warn("查询录像信息时发现节点已离线"); 1111 logger.warn("查询录像信息时发现节点已离线");
908 return null; 1112 return null;
909 } 1113 }
910 if (mediaServerItem.getRecordAssistPort() > 0) { 1114 if (mediaServerItem.getRecordAssistPort() > 0) {
911 - JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, streamInfo.getApp(), streamInfo.getStream(), null); 1115 + JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream(), null);
912 if (jsonObject == null) { 1116 if (jsonObject == null) {
913 throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接Assist服务失败"); 1117 throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接Assist服务失败");
914 } 1118 }
@@ -916,10 +1120,10 @@ public class PlayServiceImpl implements IPlayService { @@ -916,10 +1120,10 @@ public class PlayServiceImpl implements IPlayService {
916 long duration = jsonObject.getLong("data"); 1120 long duration = jsonObject.getLong("data");
917 1121
918 if (duration == 0) { 1122 if (duration == 0) {
919 - streamInfo.setProgress(0); 1123 + inviteInfo.getStreamInfo().setProgress(0);
920 } else { 1124 } else {
921 - String startTime = streamInfo.getStartTime();  
922 - String endTime = streamInfo.getEndTime(); 1125 + String startTime = inviteInfo.getStreamInfo().getStartTime();
  1126 + String endTime = inviteInfo.getStreamInfo().getEndTime();
923 long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); 1127 long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
924 long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); 1128 long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
925 1129
@@ -927,29 +1131,31 @@ public class PlayServiceImpl implements IPlayService { @@ -927,29 +1131,31 @@ public class PlayServiceImpl implements IPlayService {
927 BigDecimal totalCount = new BigDecimal(end - start); 1131 BigDecimal totalCount = new BigDecimal(end - start);
928 BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP); 1132 BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP);
929 double process = divide.doubleValue(); 1133 double process = divide.doubleValue();
930 - streamInfo.setProgress(process); 1134 + inviteInfo.getStreamInfo().setProgress(process);
931 } 1135 }
  1136 + inviteStreamService.updateInviteInfo(inviteInfo);
932 } 1137 }
933 } 1138 }
  1139 + return inviteInfo.getStreamInfo();
934 } 1140 }
935 - return streamInfo; 1141 + return null;
936 } 1142 }
937 1143
938 - @Override  
939 - public void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String uuid) {  
940 - RequestMessage msg = new RequestMessage();  
941 - msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId);  
942 - msg.setId(uuid);  
943 - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId); 1144 + private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, JSONObject response, String deviceId, String channelId, String startTime, String endTime) {
  1145 + StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, response, deviceId, channelId);
944 if (streamInfo != null) { 1146 if (streamInfo != null) {
945 - redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());  
946 - msg.setData(JSON.toJSONString(streamInfo));  
947 - resultHolder.invokeResult(msg);  
948 - } else {  
949 - logger.warn("设备预览API调用失败!");  
950 - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "设备预览API调用失败!"));  
951 - resultHolder.invokeResult(msg); 1147 + streamInfo.setProgress(0);
  1148 + streamInfo.setStartTime(startTime);
  1149 + streamInfo.setEndTime(endTime);
  1150 + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, streamInfo.getStream());
  1151 + if (inviteInfo != null) {
  1152 + logger.info("[录像下载] 更新invite消息中的stream信息");
  1153 + inviteInfo.setStatus(InviteSessionStatus.ok);
  1154 + inviteInfo.setStreamInfo(streamInfo);
  1155 + inviteStreamService.updateInviteInfo(inviteInfo);
  1156 + }
952 } 1157 }
  1158 + return streamInfo;
953 } 1159 }
954 1160
955 1161
@@ -1189,15 +1395,14 @@ public class PlayServiceImpl implements IPlayService { @@ -1189,15 +1395,14 @@ public class PlayServiceImpl implements IPlayService {
1189 1395
1190 @Override 1396 @Override
1191 public void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException { 1397 public void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException {
1192 - String key = redisCatchStorage.queryPlaybackForKey(null, null, streamId, null);  
1193 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
1194 - if (null == streamInfo) { 1398 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  1399 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
1195 logger.warn("streamId不存在!"); 1400 logger.warn("streamId不存在!");
1196 throw new ServiceException("streamId不存在"); 1401 throw new ServiceException("streamId不存在");
1197 } 1402 }
1198 - streamInfo.setPause(true);  
1199 - redisTemplate.opsForValue().set(key, streamInfo);  
1200 - MediaServerItem mediaServerItem = mediaServerService.getOne(streamInfo.getMediaServerId()); 1403 + inviteInfo.getStreamInfo().setPause(true);
  1404 + inviteStreamService.updateInviteInfo(inviteInfo);
  1405 + MediaServerItem mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
1201 if (null == mediaServerItem) { 1406 if (null == mediaServerItem) {
1202 logger.warn("mediaServer 不存在!"); 1407 logger.warn("mediaServer 不存在!");
1203 throw new ServiceException("mediaServer不存在"); 1408 throw new ServiceException("mediaServer不存在");
@@ -1207,21 +1412,20 @@ public class PlayServiceImpl implements IPlayService { @@ -1207,21 +1412,20 @@ public class PlayServiceImpl implements IPlayService {
1207 if (jsonObject == null || jsonObject.getInteger("code") != 0) { 1412 if (jsonObject == null || jsonObject.getInteger("code") != 0) {
1208 throw new ServiceException("暂停RTP接收失败"); 1413 throw new ServiceException("暂停RTP接收失败");
1209 } 1414 }
1210 - Device device = storager.queryVideoDevice(streamInfo.getDeviceID());  
1211 - cmder.playPauseCmd(device, streamInfo); 1415 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
  1416 + cmder.playPauseCmd(device, inviteInfo.getStreamInfo());
1212 } 1417 }
1213 1418
1214 @Override 1419 @Override
1215 public void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException { 1420 public void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException {
1216 - String key = redisCatchStorage.queryPlaybackForKey(null, null, streamId, null);  
1217 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
1218 - if (null == streamInfo) { 1421 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  1422 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
1219 logger.warn("streamId不存在!"); 1423 logger.warn("streamId不存在!");
1220 throw new ServiceException("streamId不存在"); 1424 throw new ServiceException("streamId不存在");
1221 } 1425 }
1222 - streamInfo.setPause(false);  
1223 - redisTemplate.opsForValue().set(key, streamInfo);  
1224 - MediaServerItem mediaServerItem = mediaServerService.getOne(streamInfo.getMediaServerId()); 1426 + inviteInfo.getStreamInfo().setPause(false);
  1427 + inviteStreamService.updateInviteInfo(inviteInfo);
  1428 + MediaServerItem mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
1225 if (null == mediaServerItem) { 1429 if (null == mediaServerItem) {
1226 logger.warn("mediaServer 不存在!"); 1430 logger.warn("mediaServer 不存在!");
1227 throw new ServiceException("mediaServer不存在"); 1431 throw new ServiceException("mediaServer不存在");
@@ -1231,8 +1435,8 @@ public class PlayServiceImpl implements IPlayService { @@ -1231,8 +1435,8 @@ public class PlayServiceImpl implements IPlayService {
1231 if (jsonObject == null || jsonObject.getInteger("code") != 0) { 1435 if (jsonObject == null || jsonObject.getInteger("code") != 0) {
1232 throw new ServiceException("继续RTP接收失败"); 1436 throw new ServiceException("继续RTP接收失败");
1233 } 1437 }
1234 - Device device = storager.queryVideoDevice(streamInfo.getDeviceID());  
1235 - cmder.playResumeCmd(device, streamInfo); 1438 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
  1439 + cmder.playResumeCmd(device, inviteInfo.getStreamInfo());
1236 } 1440 }
1237 1441
1238 @Override 1442 @Override
@@ -1308,7 +1512,7 @@ public class PlayServiceImpl implements IPlayService { @@ -1308,7 +1512,7 @@ public class PlayServiceImpl implements IPlayService {
1308 logger.info("调用ZLM推流接口, 结果: {}", jsonObject); 1512 logger.info("调用ZLM推流接口, 结果: {}", jsonObject);
1309 logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port")); 1513 logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
1310 } else { 1514 } else {
1311 - logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSON.toJSONString(param)); 1515 + logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSONObject.toJSONString(param));
1312 if (sendRtpItem.isOnlyAudio()) { 1516 if (sendRtpItem.isOnlyAudio()) {
1313 Device device = deviceService.getDevice(sendRtpItem.getDeviceId()); 1517 Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
1314 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); 1518 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
@@ -1419,7 +1623,7 @@ public class PlayServiceImpl implements IPlayService { @@ -1419,7 +1623,7 @@ public class PlayServiceImpl implements IPlayService {
1419 zlmrtpServerFactory.stopSendRtpStream(mediaServer, param); 1623 zlmrtpServerFactory.stopSendRtpStream(mediaServer, param);
1420 } 1624 }
1421 1625
1422 - mediaServer.getSsrcConfig().releaseSsrc(sendRtpItem.getSsrc()); 1626 + ssrcFactory.releaseSsrc(mediaServerId, sendRtpItem.getSsrc());
1423 1627
1424 SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, null, sendRtpItem.getStream()); 1628 SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, null, sendRtpItem.getStream());
1425 if (ssrcTransaction != null) { 1629 if (ssrcTransaction != null) {
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
@@ -264,8 +264,8 @@ public class RedisGbPlayMsgListener implements MessageListener { @@ -264,8 +264,8 @@ public class RedisGbPlayMsgListener implements MessageListener {
264 return; 264 return;
265 } 265 }
266 // 确定流是否在线 266 // 确定流是否在线
267 - boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, content.getApp(), content.getStream());  
268 - if (streamReady) { 267 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, content.getApp(), content.getStream());
  268 + if (streamReady != null && streamReady) {
269 logger.info("[回复推流信息] {}/{}", content.getApp(), content.getStream()); 269 logger.info("[回复推流信息] {}/{}", content.getApp(), content.getStream());
270 responseSendItem(mediaServerItem, content, toId, serial); 270 responseSendItem(mediaServerItem, content, toId, serial);
271 }else { 271 }else {
@@ -301,9 +301,6 @@ public class RedisGbPlayMsgListener implements MessageListener { @@ -301,9 +301,6 @@ public class RedisGbPlayMsgListener implements MessageListener {
301 String key = VideoManagerConstants.VM_MSG_STREAM_PUSH_REQUESTED; 301 String key = VideoManagerConstants.VM_MSG_STREAM_PUSH_REQUESTED;
302 logger.info("[redis发送通知] 推流被请求 {}: {}/{}", key, messageForPushChannel.getApp(), messageForPushChannel.getStream()); 302 logger.info("[redis发送通知] 推流被请求 {}: {}/{}", key, messageForPushChannel.getApp(), messageForPushChannel.getStream());
303 redisTemplate.convertAndSend(key, JSON.toJSON(messageForPushChannel)); 303 redisTemplate.convertAndSend(key, JSON.toJSON(messageForPushChannel));
304 -  
305 -// redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);  
306 -  
307 } 304 }
308 } 305 }
309 306
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java
@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.service.redisMsg; @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.service.redisMsg;
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.genersoft.iot.vmp.common.VideoManagerConstants; 4 import com.genersoft.iot.vmp.common.VideoManagerConstants;
5 import com.genersoft.iot.vmp.conf.DynamicTask; 5 import com.genersoft.iot.vmp.conf.DynamicTask;
  6 +import com.genersoft.iot.vmp.conf.UserSetting;
6 import com.genersoft.iot.vmp.service.IStreamPushService; 7 import com.genersoft.iot.vmp.service.IStreamPushService;
7 import com.genersoft.iot.vmp.service.bean.PushStreamStatusChangeFromRedisDto; 8 import com.genersoft.iot.vmp.service.bean.PushStreamStatusChangeFromRedisDto;
8 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 9 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -38,6 +39,9 @@ public class RedisPushStreamStatusMsgListener implements MessageListener, Applic @@ -38,6 +39,9 @@ public class RedisPushStreamStatusMsgListener implements MessageListener, Applic
38 @Autowired 39 @Autowired
39 private DynamicTask dynamicTask; 40 private DynamicTask dynamicTask;
40 41
  42 + @Autowired
  43 + private UserSetting userSetting;
  44 +
41 45
42 46
43 private ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>(); 47 private ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>();
@@ -89,13 +93,15 @@ public class RedisPushStreamStatusMsgListener implements MessageListener, Applic @@ -89,13 +93,15 @@ public class RedisPushStreamStatusMsgListener implements MessageListener, Applic
89 93
90 @Override 94 @Override
91 public void run(ApplicationArguments args) throws Exception { 95 public void run(ApplicationArguments args) throws Exception {
92 - // 启动时设置所有推流通道离线,发起查询请求  
93 - redisCatchStorage.sendStreamPushRequestedMsgForStatus();  
94 - dynamicTask.startDelay(VideoManagerConstants.VM_MSG_GET_ALL_ONLINE_REQUESTED, ()->{  
95 - logger.info("[REDIS消息]未收到redis回复推流设备状态,执行推流设备离线");  
96 - // 五秒收不到请求就设置通道离线,然后通知上级离线  
97 - streamPushService.allStreamOffline();  
98 - }, 5000); 96 + if (!userSetting.isUsePushingAsStatus()) {
  97 + // 启动时设置所有推流通道离线,发起查询请求
  98 + redisCatchStorage.sendStreamPushRequestedMsgForStatus();
  99 + dynamicTask.startDelay(VideoManagerConstants.VM_MSG_GET_ALL_ONLINE_REQUESTED, ()->{
  100 + logger.info("[REDIS消息]未收到redis回复推流设备状态,执行推流设备离线");
  101 + // 五秒收不到请求就设置通道离线,然后通知上级离线
  102 + streamPushService.allStreamOffline();
  103 + }, 5000);
  104 + }
99 } 105 }
100 106
101 } 107 }
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
1 package com.genersoft.iot.vmp.storager; 1 package com.genersoft.iot.vmp.storager;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
4 -import com.genersoft.iot.vmp.common.StreamInfo;  
5 import com.genersoft.iot.vmp.common.SystemAllInfo; 4 import com.genersoft.iot.vmp.common.SystemAllInfo;
6 -import com.genersoft.iot.vmp.gb28181.bean.*;  
7 -import com.genersoft.iot.vmp.media.zlm.dto.*; 5 +import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage;
  6 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  7 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  8 +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  10 +import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
8 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; 11 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
9 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; 12 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
10 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 13 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
11 -import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;  
12 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; 14 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
13 15
14 import java.util.List; 16 import java.util.List;
@@ -23,42 +25,6 @@ public interface IRedisCatchStorage { @@ -23,42 +25,6 @@ public interface IRedisCatchStorage {
23 */ 25 */
24 Long getCSEQ(); 26 Long getCSEQ();
25 27
26 - /**  
27 - * 开始播放时将流存入  
28 - *  
29 - * @param stream 流信息  
30 - * @return  
31 - */  
32 - boolean startPlay(StreamInfo stream);  
33 -  
34 -  
35 - /**  
36 - * 停止播放时删除  
37 - *  
38 - * @return  
39 - */  
40 - boolean stopPlay(StreamInfo streamInfo);  
41 -  
42 - /**  
43 - * 查询播放列表  
44 - * @return  
45 - */  
46 - StreamInfo queryPlay(StreamInfo streamInfo);  
47 -  
48 - StreamInfo queryPlayByStreamId(String steamId);  
49 -  
50 - StreamInfo queryPlayByDevice(String deviceId, String channelId);  
51 -  
52 - Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);  
53 -  
54 - boolean startPlayback(StreamInfo stream, String callId);  
55 -  
56 - boolean stopPlayback(String deviceId, String channelId, String stream, String callId);  
57 -  
58 - StreamInfo queryPlayback(String deviceId, String channelID, String stream, String callId);  
59 -  
60 - String queryPlaybackForKey(String deviceId, String channelId, String stream, String callId);  
61 -  
62 void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch); 28 void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch);
63 29
64 ParentPlatformCatch queryPlatformCatchInfo(String platformGbId); 30 ParentPlatformCatch queryPlatformCatchInfo(String platformGbId);
@@ -75,8 +41,6 @@ public interface IRedisCatchStorage { @@ -75,8 +41,6 @@ public interface IRedisCatchStorage {
75 41
76 void delPlatformRegisterInfo(String callId); 42 void delPlatformRegisterInfo(String callId);
77 43
78 - void cleanPlatformRegisterInfos();  
79 -  
80 void updateSendRTPSever(SendRtpItem sendRtpItem); 44 void updateSendRTPSever(SendRtpItem sendRtpItem);
81 45
82 /** 46 /**
@@ -103,12 +67,6 @@ public interface IRedisCatchStorage { @@ -103,12 +67,6 @@ public interface IRedisCatchStorage {
103 boolean isChannelSendingRTP(String channelId); 67 boolean isChannelSendingRTP(String channelId);
104 68
105 /** 69 /**
106 - * 清空某个设备的所有缓存  
107 - * @param deviceId 设备ID  
108 - */  
109 - void clearCatchByDeviceId(String deviceId);  
110 -  
111 - /**  
112 * 在redis添加wvp的信息 70 * 在redis添加wvp的信息
113 */ 71 */
114 void updateWVPInfo(JSONObject jsonObject, int time); 72 void updateWVPInfo(JSONObject jsonObject, int time);
@@ -148,23 +106,6 @@ public interface IRedisCatchStorage { @@ -148,23 +106,6 @@ public interface IRedisCatchStorage {
148 */ 106 */
149 void removeStream(String mediaServerId, String type); 107 void removeStream(String mediaServerId, String type);
150 108
151 - /**  
152 - * 开始下载录像时存入  
153 - * @param streamInfo  
154 - */  
155 - boolean startDownload(StreamInfo streamInfo, String callId);  
156 -  
157 - StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId);  
158 -  
159 - boolean stopDownload(String deviceId, String channelId, String stream, String callId);  
160 -  
161 - /**  
162 - * 查找第三方系统留下的国标预设值  
163 - * @param queryKey  
164 - * @return  
165 - */  
166 - ThirdPartyGB queryMemberNoGBId(String queryKey);  
167 -  
168 List<OnStreamChangedHookParam> getStreams(String mediaServerId, String pull); 109 List<OnStreamChangedHookParam> getStreams(String mediaServerId, String pull);
169 110
170 /** 111 /**
@@ -261,4 +202,6 @@ public interface IRedisCatchStorage { @@ -261,4 +202,6 @@ public interface IRedisCatchStorage {
261 List<Device> getAllDevices(); 202 List<Device> getAllDevices();
262 203
263 void removeAllDevice(); 204 void removeAllDevice();
  205 +
  206 + void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online);
264 } 207 }
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -197,6 +197,81 @@ public interface DeviceChannelMapper { @@ -197,6 +197,81 @@ public interface DeviceChannelMapper {
197 @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId}"}) 197 @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId}"})
198 void offlineByDeviceId(String deviceId); 198 void offlineByDeviceId(String deviceId);
199 199
  200 +// @Insert("<script> " +
  201 +// "insert into device_channel " +
  202 +// "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " +
  203 +// " address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
  204 +// " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " +
  205 +// " longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " +
  206 +// "values " +
  207 +// "<foreach collection='addChannels' index='index' item='item' separator=','> " +
  208 +// "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " +
  209 +// "#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," +
  210 +// "#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " +
  211 +// "#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " +
  212 +// "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " +
  213 +// "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " +
  214 +// "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " +
  215 +// "#{item.businessGroupId}, #{item.gpsTime}) " +
  216 +// "</foreach> " +
  217 +// "ON DUPLICATE KEY UPDATE " +
  218 +// "updateTime=VALUES(updateTime), " +
  219 +// "name=VALUES(name), " +
  220 +// "manufacture=VALUES(manufacture), " +
  221 +// "model=VALUES(model), " +
  222 +// "owner=VALUES(owner), " +
  223 +// "civilCode=VALUES(civilCode), " +
  224 +// "block=VALUES(block), " +
  225 +// "subCount=VALUES(subCount), " +
  226 +// "address=VALUES(address), " +
  227 +// "parental=VALUES(parental), " +
  228 +// "parentId=VALUES(parentId), " +
  229 +// "safetyWay=VALUES(safetyWay), " +
  230 +// "registerWay=VALUES(registerWay), " +
  231 +// "certNum=VALUES(certNum), " +
  232 +// "certifiable=VALUES(certifiable), " +
  233 +// "errCode=VALUES(errCode), " +
  234 +// "secrecy=VALUES(secrecy), " +
  235 +// "ipAddress=VALUES(ipAddress), " +
  236 +// "port=VALUES(port), " +
  237 +// "password=VALUES(password), " +
  238 +// "PTZType=VALUES(PTZType), " +
  239 +// "status=VALUES(status), " +
  240 +// "streamId=VALUES(streamId), " +
  241 +// "longitude=VALUES(longitude), " +
  242 +// "latitude=VALUES(latitude), " +
  243 +// "longitudeGcj02=VALUES(longitudeGcj02), " +
  244 +// "latitudeGcj02=VALUES(latitudeGcj02), " +
  245 +// "longitudeWgs84=VALUES(longitudeWgs84), " +
  246 +// "latitudeWgs84=VALUES(latitudeWgs84), " +
  247 +// "hasAudio=VALUES(hasAudio), " +
  248 +// "businessGroupId=VALUES(businessGroupId), " +
  249 +// "gpsTime=VALUES(gpsTime)" +
  250 +// "</script>")
  251 +// int batchAdd(List<DeviceChannel> addChannels);
  252 +
  253 +
  254 + @Insert("<script> " +
  255 + "insert into device_channel " +
  256 + "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " +
  257 + " address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
  258 + " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " +
  259 + " longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " +
  260 + "values " +
  261 + "<foreach collection='addChannels' index='index' item='item' separator=','> " +
  262 + "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " +
  263 + "#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," +
  264 + "#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " +
  265 + "#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " +
  266 + "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " +
  267 + "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " +
  268 + "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " +
  269 + "#{item.businessGroupId}, #{item.gpsTime}) " +
  270 + "</foreach> " +
  271 + "</script>")
  272 + int batchAdd(List<DeviceChannel> addChannels);
  273 +
  274 +
200 @Insert("<script> " + 275 @Insert("<script> " +
201 "insert into device_channel " + 276 "insert into device_channel " +
202 "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " + 277 "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " +
@@ -248,7 +323,7 @@ public interface DeviceChannelMapper { @@ -248,7 +323,7 @@ public interface DeviceChannelMapper {
248 "businessGroupId=VALUES(businessGroupId), " + 323 "businessGroupId=VALUES(businessGroupId), " +
249 "gpsTime=VALUES(gpsTime)" + 324 "gpsTime=VALUES(gpsTime)" +
250 "</script>") 325 "</script>")
251 - int batchAdd(List<DeviceChannel> addChannels); 326 + int batchAddOrUpdate(List<DeviceChannel> addChannels);
252 327
253 @Update(value = {"UPDATE device_channel SET status=1 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) 328 @Update(value = {"UPDATE device_channel SET status=1 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"})
254 void online(String deviceId, String channelId); 329 void online(String deviceId, String channelId);
@@ -264,7 +339,7 @@ public interface DeviceChannelMapper { @@ -264,7 +339,7 @@ public interface DeviceChannelMapper {
264 "<if test='item.owner != null'>, owner=#{item.owner}</if>" + 339 "<if test='item.owner != null'>, owner=#{item.owner}</if>" +
265 "<if test='item.civilCode != null'>, civilCode=#{item.civilCode}</if>" + 340 "<if test='item.civilCode != null'>, civilCode=#{item.civilCode}</if>" +
266 "<if test='item.block != null'>, block=#{item.block}</if>" + 341 "<if test='item.block != null'>, block=#{item.block}</if>" +
267 - "<if test='item.subCount != null'>, block=#{item.subCount}</if>" + 342 + "<if test='item.subCount != null'>, subCount=#{item.subCount}</if>" +
268 "<if test='item.address != null'>, address=#{item.address}</if>" + 343 "<if test='item.address != null'>, address=#{item.address}</if>" +
269 "<if test='item.parental != null'>, parental=#{item.parental}</if>" + 344 "<if test='item.parental != null'>, parental=#{item.parental}</if>" +
270 "<if test='item.parentId != null'>, parentId=#{item.parentId}</if>" + 345 "<if test='item.parentId != null'>, parentId=#{item.parentId}</if>" +
@@ -289,7 +364,8 @@ public interface DeviceChannelMapper { @@ -289,7 +364,8 @@ public interface DeviceChannelMapper {
289 "<if test='item.latitudeWgs84 != null'>, latitudeWgs84=#{item.latitudeWgs84}</if>" + 364 "<if test='item.latitudeWgs84 != null'>, latitudeWgs84=#{item.latitudeWgs84}</if>" +
290 "<if test='item.businessGroupId != null'>, businessGroupId=#{item.businessGroupId}</if>" + 365 "<if test='item.businessGroupId != null'>, businessGroupId=#{item.businessGroupId}</if>" +
291 "<if test='item.gpsTime != null'>, gpsTime=#{item.gpsTime}</if>" + 366 "<if test='item.gpsTime != null'>, gpsTime=#{item.gpsTime}</if>" +
292 - "WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}"+ 367 + "<if test='item.id > 0'>WHERE id=#{item.id}</if>" +
  368 + "<if test='item.id == 0'>WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}</if>" +
293 "</foreach>" + 369 "</foreach>" +
294 "</script>"}) 370 "</script>"})
295 int batchUpdate(List<DeviceChannel> updateChannels); 371 int batchUpdate(List<DeviceChannel> updateChannels);
@@ -403,4 +479,26 @@ public interface DeviceChannelMapper { @@ -403,4 +479,26 @@ public interface DeviceChannelMapper {
403 479
404 @Select("select de.* from device de left join device_channel dc on de.deviceId = dc.deviceId where dc.channelId=#{channelId}") 480 @Select("select de.* from device de left join device_channel dc on de.deviceId = dc.deviceId where dc.channelId=#{channelId}")
405 List<Device> getDeviceByChannelId(String channelId); 481 List<Device> getDeviceByChannelId(String channelId);
  482 +
  483 +
  484 + @Delete({"<script>" +
  485 + "<foreach collection='deleteChannelList' item='item' separator=';'>" +
  486 + "DELETE FROM device_channel WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}" +
  487 + "</foreach>" +
  488 + "</script>"})
  489 + int batchDel(List<DeviceChannel> deleteChannelList);
  490 +
  491 + @Update({"<script>" +
  492 + "<foreach collection='channels' item='item' separator=';'>" +
  493 + "UPDATE device_channel SET status=1 WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}" +
  494 + "</foreach>" +
  495 + "</script>"})
  496 + int batchOnline(List<DeviceChannel> channels);
  497 +
  498 + @Update({"<script>" +
  499 + "<foreach collection='channels' item='item' separator=';'>" +
  500 + "UPDATE device_channel SET status=0 WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}" +
  501 + "</foreach>" +
  502 + "</script>"})
  503 + int batchOffline(List<DeviceChannel> channels);
406 } 504 }
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -2,17 +2,18 @@ package com.genersoft.iot.vmp.storager.impl; @@ -2,17 +2,18 @@ package com.genersoft.iot.vmp.storager.impl;
2 2
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
4 import com.alibaba.fastjson2.JSONObject; 4 import com.alibaba.fastjson2.JSONObject;
5 -import com.genersoft.iot.vmp.common.StreamInfo;  
6 import com.genersoft.iot.vmp.common.SystemAllInfo; 5 import com.genersoft.iot.vmp.common.SystemAllInfo;
7 import com.genersoft.iot.vmp.common.VideoManagerConstants; 6 import com.genersoft.iot.vmp.common.VideoManagerConstants;
8 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
9 -import com.genersoft.iot.vmp.gb28181.bean.*;  
10 -import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; 8 +import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage;
  9 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  10 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  11 +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 12 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; 13 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
  14 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
13 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; 15 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
14 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 16 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
15 -import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;  
16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 17 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
17 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; 18 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
18 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; 19 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
@@ -24,8 +25,10 @@ import org.slf4j.Logger; @@ -24,8 +25,10 @@ import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory; 25 import org.slf4j.LoggerFactory;
25 import org.springframework.beans.factory.annotation.Autowired; 26 import org.springframework.beans.factory.annotation.Autowired;
26 import org.springframework.data.redis.core.RedisTemplate; 27 import org.springframework.data.redis.core.RedisTemplate;
  28 +import org.springframework.data.redis.core.StringRedisTemplate;
27 import org.springframework.stereotype.Component; 29 import org.springframework.stereotype.Component;
28 30
  31 +import java.time.Duration;
29 import java.util.*; 32 import java.util.*;
30 33
31 @SuppressWarnings("rawtypes") 34 @SuppressWarnings("rawtypes")
@@ -43,6 +46,9 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -43,6 +46,9 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
43 @Autowired 46 @Autowired
44 private RedisTemplate<Object, Object> redisTemplate; 47 private RedisTemplate<Object, Object> redisTemplate;
45 48
  49 + @Autowired
  50 + private StringRedisTemplate stringRedisTemplate;
  51 +
46 @Override 52 @Override
47 public Long getCSEQ() { 53 public Long getCSEQ() {
48 String key = VideoManagerConstants.SIP_CSEQ_PREFIX + userSetting.getServerId(); 54 String key = VideoManagerConstants.SIP_CSEQ_PREFIX + userSetting.getServerId();
@@ -87,240 +93,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -87,240 +93,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
87 } 93 }
88 } 94 }
89 95
90 - /**  
91 - * 开始播放时将流存入redis  
92 - */  
93 - @Override  
94 - public boolean startPlay(StreamInfo stream) {  
95 -  
96 - redisTemplate.opsForValue().set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, userSetting.getServerId(),  
97 - stream.getMediaServerId(), stream.getStream(), stream.getDeviceID(), stream.getChannelId()),  
98 - stream);  
99 - return true;  
100 - }  
101 -  
102 - /**  
103 - * 停止播放时从redis删除  
104 - */  
105 - @Override  
106 - public boolean stopPlay(StreamInfo streamInfo) {  
107 - if (streamInfo == null) {  
108 - return false;  
109 - }  
110 - Boolean result = redisTemplate.delete(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,  
111 - userSetting.getServerId(),  
112 - streamInfo.getMediaServerId(),  
113 - streamInfo.getStream(),  
114 - streamInfo.getDeviceID(),  
115 - streamInfo.getChannelId()));  
116 - return result != null && result;  
117 - }  
118 -  
119 - /**  
120 - * 查询播放列表  
121 - */  
122 - @Override  
123 - public StreamInfo queryPlay(StreamInfo streamInfo) {  
124 - return (StreamInfo)redisTemplate.opsForValue().get(String.format("%S_%s_%s_%s_%s_%s",  
125 - VideoManagerConstants.PLAYER_PREFIX,  
126 - userSetting.getServerId(),  
127 - streamInfo.getMediaServerId(),  
128 - streamInfo.getStream(),  
129 - streamInfo.getDeviceID(),  
130 - streamInfo.getChannelId()));  
131 - }  
132 - @Override  
133 - public StreamInfo queryPlayByStreamId(String streamId) {  
134 - List<Object> playLeys = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_%s_*", VideoManagerConstants.PLAYER_PREFIX, userSetting.getServerId(), streamId));  
135 - if (playLeys.size() == 0) {  
136 - return null;  
137 - }  
138 - return (StreamInfo)redisTemplate.opsForValue().get(playLeys.get(0).toString());  
139 - }  
140 -  
141 - @Override  
142 - public StreamInfo queryPlayByDevice(String deviceId, String channelId) {  
143 - List<Object> playLeys = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,  
144 - userSetting.getServerId(),  
145 - deviceId,  
146 - channelId));  
147 - if (playLeys.size() == 0) {  
148 - return null;  
149 - }  
150 - return (StreamInfo)redisTemplate.opsForValue().get(playLeys.get(0).toString());  
151 - }  
152 -  
153 - @Override  
154 - public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {  
155 - Map<String, StreamInfo> streamInfos = new HashMap<>();  
156 - List<Object> players = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_*_%s_*", VideoManagerConstants.PLAYER_PREFIX, userSetting.getServerId(),deviceId));  
157 - if (players.size() == 0) {  
158 - return streamInfos;  
159 - }  
160 - for (Object player : players) {  
161 - String key = (String) player;  
162 - StreamInfo streamInfo = JsonUtil.redisJsonToObject(redisTemplate, key, StreamInfo.class);  
163 - if (Objects.isNull(streamInfo)) {  
164 - continue;  
165 - }  
166 - streamInfos.put(streamInfo.getDeviceID() + "_" + streamInfo.getChannelId(), streamInfo);  
167 - }  
168 - return streamInfos;  
169 - }  
170 -  
171 -  
172 - @Override  
173 - public boolean startPlayback(StreamInfo stream, String callId) {  
174 - redisTemplate.opsForValue().set(String.format("%S_%s_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,  
175 - userSetting.getServerId(), stream.getMediaServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream);  
176 - return true;  
177 - }  
178 -  
179 - @Override  
180 - public boolean startDownload(StreamInfo stream, String callId) {  
181 - String key=String.format("%S_%s_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,  
182 - userSetting.getServerId(), stream.getMediaServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId);  
183 - if (stream.getProgress() == 1) {  
184 - logger.debug("添加下载缓存==已完成下载=》{}",key);  
185 - redisTemplate.opsForValue().set(key, stream);  
186 - }else {  
187 - logger.debug("添加下载缓存==未完成下载=》{}",key);  
188 - redisTemplate.opsForValue().set(key, stream, 60*60);  
189 - }  
190 - return true;  
191 - }  
192 - @Override  
193 - public boolean stopDownload(String deviceId, String channelId, String stream, String callId) {  
194 - DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);  
195 - if (deviceChannel != null) {  
196 - deviceChannel.setStreamId(null);  
197 - deviceChannel.setDeviceId(deviceId);  
198 - deviceChannelMapper.update(deviceChannel);  
199 - }  
200 - if (deviceId == null) {  
201 - deviceId = "*";  
202 - }  
203 - if (channelId == null) {  
204 - channelId = "*";  
205 - }  
206 - if (stream == null) {  
207 - stream = "*";  
208 - }  
209 - if (callId == null) {  
210 - callId = "*";  
211 - }  
212 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,  
213 - userSetting.getServerId(),  
214 - deviceId,  
215 - channelId,  
216 - stream,  
217 - callId  
218 - );  
219 - List<Object> scan = RedisUtil.scan(redisTemplate, key);  
220 - if (scan.size() > 0) {  
221 - for (Object keyObj : scan) {  
222 - redisTemplate.delete(keyObj);  
223 - }  
224 - }  
225 - return true;  
226 - }  
227 -  
228 - @Override  
229 - public boolean stopPlayback(String deviceId, String channelId, String stream, String callId) {  
230 - DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);  
231 - if (deviceChannel != null) {  
232 - deviceChannel.setStreamId(null);  
233 - deviceChannel.setDeviceId(deviceId);  
234 - deviceChannelMapper.update(deviceChannel);  
235 - }  
236 - if (deviceId == null) {  
237 - deviceId = "*";  
238 - }  
239 - if (channelId == null) {  
240 - channelId = "*";  
241 - }  
242 - if (stream == null) {  
243 - stream = "*";  
244 - }  
245 - if (callId == null) {  
246 - callId = "*";  
247 - }  
248 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,  
249 - userSetting.getServerId(),  
250 - deviceId,  
251 - channelId,  
252 - stream,  
253 - callId  
254 - );  
255 - List<Object> scan = RedisUtil.scan(redisTemplate, key);  
256 - if (scan.size() > 0) {  
257 - for (Object keyObj : scan) {  
258 - redisTemplate.delete(keyObj);  
259 - }  
260 - }  
261 - return true;  
262 - }  
263 -  
264 - @Override  
265 - public StreamInfo queryPlayback(String deviceId, String channelId, String stream, String callId) {  
266 - if (stream == null && callId == null) {  
267 - return null;  
268 - }  
269 - if (deviceId == null) {  
270 - deviceId = "*";  
271 - }  
272 - if (channelId == null) {  
273 - channelId = "*";  
274 - }  
275 - if (stream == null) {  
276 - stream = "*";  
277 - }  
278 - if (callId == null) {  
279 - callId = "*";  
280 - }  
281 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,  
282 - userSetting.getServerId(),  
283 - deviceId,  
284 - channelId,  
285 - stream,  
286 - callId  
287 - );  
288 - List<Object> streamInfoScan = RedisUtil.scan(redisTemplate, key);  
289 - if (streamInfoScan.size() > 0) {  
290 - return (StreamInfo) redisTemplate.opsForValue().get(streamInfoScan.get(0));  
291 - }else {  
292 - return null;  
293 - }  
294 - }  
295 -  
296 - @Override  
297 - public String queryPlaybackForKey(String deviceId, String channelId, String stream, String callId) {  
298 - if (stream == null && callId == null) {  
299 - return null;  
300 - }  
301 - if (deviceId == null) {  
302 - deviceId = "*";  
303 - }  
304 - if (channelId == null) {  
305 - channelId = "*";  
306 - }  
307 - if (stream == null) {  
308 - stream = "*";  
309 - }  
310 - if (callId == null) {  
311 - callId = "*";  
312 - }  
313 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,  
314 - userSetting.getServerId(),  
315 - deviceId,  
316 - channelId,  
317 - stream,  
318 - callId  
319 - );  
320 - List<Object> streamInfoScan = RedisUtil.scan(redisTemplate, key);  
321 - return (String) streamInfoScan.get(0);  
322 - }  
323 -  
324 @Override 96 @Override
325 public void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch) { 97 public void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch) {
326 String key = VideoManagerConstants.PLATFORM_CATCH_PREFIX + userSetting.getServerId() + "_" + parentPlatformCatch.getId(); 98 String key = VideoManagerConstants.PLATFORM_CATCH_PREFIX + userSetting.getServerId() + "_" + parentPlatformCatch.getId();
@@ -351,7 +123,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -351,7 +123,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
351 @Override 123 @Override
352 public void updatePlatformRegisterInfo(String callId, PlatformRegisterInfo platformRegisterInfo) { 124 public void updatePlatformRegisterInfo(String callId, PlatformRegisterInfo platformRegisterInfo) {
353 String key = VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetting.getServerId() + "_" + callId; 125 String key = VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetting.getServerId() + "_" + callId;
354 - redisTemplate.opsForValue().set(key, platformRegisterInfo, 30); 126 + Duration duration = Duration.ofSeconds(30L);
  127 + redisTemplate.opsForValue().set(key, platformRegisterInfo, duration);
355 } 128 }
356 129
357 130
@@ -366,14 +139,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -366,14 +139,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
366 } 139 }
367 140
368 @Override 141 @Override
369 - public void cleanPlatformRegisterInfos() {  
370 - List regInfos = RedisUtil.scan(redisTemplate, VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetting.getServerId() + "_" + "*");  
371 - for (Object key : regInfos) {  
372 - redisTemplate.delete(key.toString());  
373 - }  
374 - }  
375 -  
376 - @Override  
377 public void updateSendRTPSever(SendRtpItem sendRtpItem) { 142 public void updateSendRTPSever(SendRtpItem sendRtpItem) {
378 143
379 String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + 144 String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX +
@@ -530,39 +295,10 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -530,39 +295,10 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
530 } 295 }
531 296
532 @Override 297 @Override
533 - public void clearCatchByDeviceId(String deviceId) {  
534 - List<Object> playLeys = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_%s_*", VideoManagerConstants.PLAYER_PREFIX,  
535 - userSetting.getServerId(),  
536 - deviceId));  
537 - if (playLeys.size() > 0) {  
538 - for (Object key : playLeys) {  
539 - redisTemplate.delete(key.toString());  
540 - }  
541 - }  
542 -  
543 - List<Object> playBackers = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_%s_*_*_*", VideoManagerConstants.PLAY_BLACK_PREFIX,  
544 - userSetting.getServerId(),  
545 - deviceId));  
546 - if (playBackers.size() > 0) {  
547 - for (Object key : playBackers) {  
548 - redisTemplate.delete(key.toString());  
549 - }  
550 - }  
551 -  
552 - List<Object> deviceCache = RedisUtil.scan(redisTemplate, String.format("%S%s_%s", VideoManagerConstants.DEVICE_PREFIX,  
553 - userSetting.getServerId(),  
554 - deviceId));  
555 - if (deviceCache.size() > 0) {  
556 - for (Object key : deviceCache) {  
557 - redisTemplate.delete(key.toString());  
558 - }  
559 - }  
560 - }  
561 -  
562 - @Override  
563 public void updateWVPInfo(JSONObject jsonObject, int time) { 298 public void updateWVPInfo(JSONObject jsonObject, int time) {
564 String key = VideoManagerConstants.WVP_SERVER_PREFIX + userSetting.getServerId(); 299 String key = VideoManagerConstants.WVP_SERVER_PREFIX + userSetting.getServerId();
565 - redisTemplate.opsForValue().set(key, jsonObject, time); 300 + Duration duration = Duration.ofSeconds(time);
  301 + redisTemplate.opsForValue().set(key, jsonObject, duration);
566 } 302 }
567 303
568 @Override 304 @Override
@@ -590,44 +326,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -590,44 +326,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
590 } 326 }
591 327
592 @Override 328 @Override
593 - public StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId) {  
594 - if (stream == null && callId == null) {  
595 - return null;  
596 - }  
597 - if (deviceId == null) {  
598 - deviceId = "*";  
599 - }  
600 - if (channelId == null) {  
601 - channelId = "*";  
602 - }  
603 - if (stream == null) {  
604 - stream = "*";  
605 - }  
606 - if (callId == null) {  
607 - callId = "*";  
608 - }  
609 - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,  
610 - userSetting.getServerId(),  
611 - deviceId,  
612 - channelId,  
613 - stream,  
614 - callId  
615 - );  
616 - List<Object> streamInfoScan = RedisUtil.scan(redisTemplate, key);  
617 - if (streamInfoScan.size() > 0) {  
618 - return (StreamInfo) redisTemplate.opsForValue().get(streamInfoScan.get(0));  
619 - }else {  
620 - return null;  
621 - }  
622 - }  
623 -  
624 - @Override  
625 - public ThirdPartyGB queryMemberNoGBId(String queryKey) {  
626 - String key = VideoManagerConstants.WVP_STREAM_GB_ID_PREFIX + queryKey;  
627 - return JsonUtil.redisJsonToObject(redisTemplate, key, ThirdPartyGB.class);  
628 - }  
629 -  
630 - @Override  
631 public void removeStream(String mediaServerId, String type) { 329 public void removeStream(String mediaServerId, String type) {
632 String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetting.getServerId() + "_" + type + "_*_*_" + mediaServerId; 330 String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetting.getServerId() + "_" + type + "_*_*_" + mediaServerId;
633 List<Object> streams = RedisUtil.scan(redisTemplate, key); 331 List<Object> streams = RedisUtil.scan(redisTemplate, key);
@@ -694,7 +392,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -694,7 +392,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
694 @Override 392 @Override
695 public void updateGpsMsgInfo(GPSMsgInfo gpsMsgInfo) { 393 public void updateGpsMsgInfo(GPSMsgInfo gpsMsgInfo) {
696 String key = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetting.getServerId() + "_" + gpsMsgInfo.getId(); 394 String key = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetting.getServerId() + "_" + gpsMsgInfo.getId();
697 - redisTemplate.opsForValue().set(key, gpsMsgInfo, 60); // 默认GPS消息保存1分钟 395 + Duration duration = Duration.ofSeconds(60L);
  396 + redisTemplate.opsForValue().set(key, gpsMsgInfo, duration); // 默认GPS消息保存1分钟
698 } 397 }
699 398
700 @Override 399 @Override
@@ -902,4 +601,23 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -902,4 +601,23 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
902 + userSetting.getServerId() + "_*_" + id + "_*"; 601 + userSetting.getServerId() + "_*_" + id + "_*";
903 return RedisUtil.scan(redisTemplate, key).size(); 602 return RedisUtil.scan(redisTemplate, key).size();
904 } 603 }
  604 +
  605 + @Override
  606 + public void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online) {
  607 + String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_DEVICE_STATUS;
  608 + if (channelId == null) {
  609 + logger.info("[redis通知] 推送设备状态, {}-{}", deviceId, online);
  610 + }else {
  611 + logger.info("[redis通知] 推送通道状态, {}/{}-{}", deviceId, channelId, online);
  612 + }
  613 +
  614 + StringBuilder msg = new StringBuilder();
  615 + msg.append(deviceId);
  616 + if (channelId != null) {
  617 + msg.append(":").append(channelId);
  618 + }
  619 + msg.append(" ").append(online? "ON":"OFF");
  620 + // 使用 RedisTemplate<Object, Object> 发送字符串消息会导致发送的消息多带了双引号
  621 + stringRedisTemplate.convertAndSend(key, msg.toString());
  622 + }
905 } 623 }
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -177,10 +177,10 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -177,10 +177,10 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
177 if (i + limitCount > channels.size()) { 177 if (i + limitCount > channels.size()) {
178 toIndex = channels.size(); 178 toIndex = channels.size();
179 } 179 }
180 - result = result || deviceChannelMapper.batchAdd(channels.subList(i, toIndex)) < 0; 180 + result = result || deviceChannelMapper.batchAddOrUpdate(channels.subList(i, toIndex)) < 0;
181 } 181 }
182 }else { 182 }else {
183 - result = result || deviceChannelMapper.batchAdd(channels) < 0; 183 + result = result || deviceChannelMapper.batchAddOrUpdate(channels) < 0;
184 } 184 }
185 } 185 }
186 if (result) { 186 if (result) {
@@ -278,10 +278,10 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -278,10 +278,10 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
278 if (i + limitCount > addChannels.size()) { 278 if (i + limitCount > addChannels.size()) {
279 toIndex = addChannels.size(); 279 toIndex = addChannels.size();
280 } 280 }
281 - result = result || deviceChannelMapper.batchAdd(addChannels.subList(i, toIndex)) < 0; 281 + result = result || deviceChannelMapper.batchAddOrUpdate(addChannels.subList(i, toIndex)) < 0;
282 } 282 }
283 }else { 283 }else {
284 - result = result || deviceChannelMapper.batchAdd(addChannels) < 0; 284 + result = result || deviceChannelMapper.batchAddOrUpdate(addChannels) < 0;
285 } 285 }
286 } 286 }
287 if (updateChannels.size() > 0) { 287 if (updateChannels.size() > 0) {
@@ -434,9 +434,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -434,9 +434,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
434 */ 434 */
435 @Override 435 @Override
436 public synchronized boolean insertMobilePosition(MobilePosition mobilePosition) { 436 public synchronized boolean insertMobilePosition(MobilePosition mobilePosition) {
437 - if (mobilePosition.getDeviceId().equals(mobilePosition.getChannelId())) {  
438 - mobilePosition.setChannelId(null);  
439 - }  
440 return deviceMobilePositionMapper.insertNewPosition(mobilePosition) > 0; 437 return deviceMobilePositionMapper.insertNewPosition(mobilePosition) > 0;
441 } 438 }
442 439
src/main/java/com/genersoft/iot/vmp/utils/ConfigConst.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.utils;  
2 -  
3 -public class ConfigConst {  
4 - /**  
5 - * 播流最大并发个数  
6 - */  
7 - public static final Integer MAX_STRTEAM_COUNT = 10000;  
8 -}  
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; @@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
15 import com.genersoft.iot.vmp.service.IDeviceChannelService; 15 import com.genersoft.iot.vmp.service.IDeviceChannelService;
16 import com.genersoft.iot.vmp.service.IDeviceService; 16 import com.genersoft.iot.vmp.service.IDeviceService;
  17 +import com.genersoft.iot.vmp.service.IInviteStreamService;
17 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 18 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
18 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 19 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
19 import com.genersoft.iot.vmp.vmanager.bean.BaseTree; 20 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
@@ -62,6 +63,9 @@ public class DeviceQuery { @@ -62,6 +63,9 @@ public class DeviceQuery {
62 63
63 @Autowired 64 @Autowired
64 private IRedisCatchStorage redisCatchStorage; 65 private IRedisCatchStorage redisCatchStorage;
  66 +
  67 + @Autowired
  68 + private IInviteStreamService inviteStreamService;
65 69
66 @Autowired 70 @Autowired
67 private SIPCommander cmder; 71 private SIPCommander cmder;
@@ -184,7 +188,7 @@ public class DeviceQuery { @@ -184,7 +188,7 @@ public class DeviceQuery {
184 // 清除redis记录 188 // 清除redis记录
185 boolean isSuccess = deviceService.delete(deviceId); 189 boolean isSuccess = deviceService.delete(deviceId);
186 if (isSuccess) { 190 if (isSuccess) {
187 - redisCatchStorage.clearCatchByDeviceId(deviceId); 191 + inviteStreamService.clearInviteInfo(deviceId);
188 // 停止此设备的订阅更新 192 // 停止此设备的订阅更新
189 Set<String> allKeys = dynamicTask.getAllKeys(); 193 Set<String> allKeys = dynamicTask.getAllKeys();
190 for (String key : allKeys) { 194 for (String key : allKeys) {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.vmanager.gb28181.play; @@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.vmanager.gb28181.play;
2 2
3 import com.alibaba.fastjson2.JSONArray; 3 import com.alibaba.fastjson2.JSONArray;
4 import com.alibaba.fastjson2.JSONObject; 4 import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.InviteInfo;
  6 +import com.genersoft.iot.vmp.common.InviteSessionStatus;
  7 +import com.genersoft.iot.vmp.common.InviteSessionType;
5 import com.genersoft.iot.vmp.common.StreamInfo; 8 import com.genersoft.iot.vmp.common.StreamInfo;
6 import com.genersoft.iot.vmp.conf.UserSetting; 9 import com.genersoft.iot.vmp.conf.UserSetting;
7 import com.genersoft.iot.vmp.conf.exception.ControllerException; 10 import com.genersoft.iot.vmp.conf.exception.ControllerException;
@@ -14,12 +17,17 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; @@ -14,12 +17,17 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 17 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
15 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; 18 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
16 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 19 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  20 +import com.genersoft.iot.vmp.service.IInviteStreamService;
17 import com.genersoft.iot.vmp.service.IMediaServerService; 21 import com.genersoft.iot.vmp.service.IMediaServerService;
18 import com.genersoft.iot.vmp.service.IMediaService; 22 import com.genersoft.iot.vmp.service.IMediaService;
19 import com.genersoft.iot.vmp.service.IPlayService; 23 import com.genersoft.iot.vmp.service.IPlayService;
  24 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 25 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
21 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 26 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
22 import com.genersoft.iot.vmp.vmanager.bean.*; 27 import com.genersoft.iot.vmp.vmanager.bean.*;
  28 +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  29 +import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
  30 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
23 import io.swagger.v3.oas.annotations.Operation; 31 import io.swagger.v3.oas.annotations.Operation;
24 import io.swagger.v3.oas.annotations.Parameter; 32 import io.swagger.v3.oas.annotations.Parameter;
25 import io.swagger.v3.oas.annotations.tags.Tag; 33 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -61,6 +69,9 @@ public class PlayController { @@ -61,6 +69,9 @@ public class PlayController {
61 private IRedisCatchStorage redisCatchStorage; 69 private IRedisCatchStorage redisCatchStorage;
62 70
63 @Autowired 71 @Autowired
  72 + private IInviteStreamService inviteStreamService;
  73 +
  74 + @Autowired
64 private ZLMRESTfulUtils zlmresTfulUtils; 75 private ZLMRESTfulUtils zlmresTfulUtils;
65 76
66 @Autowired 77 @Autowired
@@ -89,14 +100,12 @@ public class PlayController { @@ -89,14 +100,12 @@ public class PlayController {
89 Device device = storager.queryVideoDevice(deviceId); 100 Device device = storager.queryVideoDevice(deviceId);
90 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); 101 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
91 102
92 - RequestMessage msg = new RequestMessage(); 103 + RequestMessage requestMessage = new RequestMessage();
93 String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; 104 String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
94 - boolean exist = resultHolder.exist(key, null);  
95 - msg.setKey(key); 105 + requestMessage.setKey(key);
96 String uuid = UUID.randomUUID().toString(); 106 String uuid = UUID.randomUUID().toString();
97 - msg.setId(uuid); 107 + requestMessage.setId(uuid);
98 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); 108 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
99 - DeferredResultEx<WVPResult<StreamContent>> deferredResultEx = new DeferredResultEx<>(result);  
100 109
101 result.onTimeout(()->{ 110 result.onTimeout(()->{
102 logger.info("点播接口等待超时"); 111 logger.info("点播接口等待超时");
@@ -104,32 +113,33 @@ public class PlayController { @@ -104,32 +113,33 @@ public class PlayController {
104 WVPResult<StreamInfo> wvpResult = new WVPResult<>(); 113 WVPResult<StreamInfo> wvpResult = new WVPResult<>();
105 wvpResult.setCode(ErrorCode.ERROR100.getCode()); 114 wvpResult.setCode(ErrorCode.ERROR100.getCode());
106 wvpResult.setMsg("点播超时"); 115 wvpResult.setMsg("点播超时");
107 - msg.setData(wvpResult);  
108 - resultHolder.invokeResult(msg);  
109 - });  
110 - // TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误  
111 - deferredResultEx.setFilter(result1 -> {  
112 - WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1;  
113 - WVPResult<StreamContent> resultStream = new WVPResult<>();  
114 - resultStream.setCode(wvpResult1.getCode());  
115 - resultStream.setMsg(wvpResult1.getMsg());  
116 - if (wvpResult1.getCode() == ErrorCode.SUCCESS.getCode()) {  
117 - StreamInfo data = wvpResult1.getData().clone();  
118 - if (userSetting.getUseSourceIpAsStreamIp()) {  
119 - data.channgeStreamIp(request.getLocalName());  
120 - }  
121 - resultStream.setData(new StreamContent(wvpResult1.getData()));  
122 - }  
123 - return resultStream; 116 + requestMessage.setData(wvpResult);
  117 + resultHolder.invokeResult(requestMessage);
124 }); 118 });
125 119
126 -  
127 // 录像查询以channelId作为deviceId查询 120 // 录像查询以channelId作为deviceId查询
128 - resultHolder.put(key, uuid, deferredResultEx); 121 + resultHolder.put(key, uuid, result);
129 122
130 - if (!exist) {  
131 - playService.play(newMediaServerItem, deviceId, channelId, null, null, null);  
132 - } 123 + playService.play(newMediaServerItem, deviceId, channelId, (code, msg, data) -> {
  124 + WVPResult<StreamContent> wvpResult = new WVPResult<>();
  125 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  126 + wvpResult.setCode(ErrorCode.SUCCESS.getCode());
  127 + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
  128 +
  129 + if (data != null) {
  130 + StreamInfo streamInfo = (StreamInfo)data;
  131 + if (userSetting.getUseSourceIpAsStreamIp()) {
  132 + streamInfo.channgeStreamIp(request.getLocalName());
  133 + }
  134 + wvpResult.setData(new StreamContent(streamInfo));
  135 + }
  136 + }else {
  137 + wvpResult.setCode(code);
  138 + wvpResult.setMsg(msg);
  139 + }
  140 + requestMessage.setData(wvpResult);
  141 + resultHolder.invokeResult(requestMessage);
  142 + });
133 return result; 143 return result;
134 } 144 }
135 145
@@ -150,21 +160,22 @@ public class PlayController { @@ -150,21 +160,22 @@ public class PlayController {
150 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备[" + deviceId + "]不存在"); 160 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备[" + deviceId + "]不存在");
151 } 161 }
152 162
153 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);  
154 - if (streamInfo == null) { 163 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  164 + if (inviteInfo == null) {
155 throw new ControllerException(ErrorCode.ERROR100.getCode(), "点播未找到"); 165 throw new ControllerException(ErrorCode.ERROR100.getCode(), "点播未找到");
156 } 166 }
157 -  
158 - try {  
159 - logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);  
160 - cmder.streamByeCmd(device, channelId, streamInfo.getStream(), null, null);  
161 - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {  
162 - logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());  
163 - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); 167 + if (InviteSessionStatus.ok == inviteInfo.getStatus()) {
  168 + try {
  169 + logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
  170 + cmder.streamByeCmd(device, channelId, inviteInfo.getStream(), null, null);
  171 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  172 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
  173 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
  174 + }
164 } 175 }
165 - redisCatchStorage.stopPlay(streamInfo); 176 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
166 177
167 - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 178 + storager.stopPlay(deviceId, channelId);
168 JSONObject json = new JSONObject(); 179 JSONObject json = new JSONObject();
169 json.put("deviceId", deviceId); 180 json.put("deviceId", deviceId);
170 json.put("channelId", channelId); 181 json.put("channelId", channelId);
@@ -179,15 +190,14 @@ public class PlayController { @@ -179,15 +190,14 @@ public class PlayController {
179 @Parameter(name = "streamId", description = "视频流ID", required = true) 190 @Parameter(name = "streamId", description = "视频流ID", required = true)
180 @PostMapping("/convert/{streamId}") 191 @PostMapping("/convert/{streamId}")
181 public JSONObject playConvert(@PathVariable String streamId) { 192 public JSONObject playConvert(@PathVariable String streamId) {
182 - StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);  
183 - if (streamInfo == null) {  
184 - streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
185 - }  
186 - if (streamInfo == null) { 193 +// StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
  194 +
  195 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, streamId);
  196 + if (inviteInfo == null || inviteInfo.getStreamInfo() == null) {
187 logger.warn("视频转码API调用失败!, 视频流已经停止!"); 197 logger.warn("视频转码API调用失败!, 视频流已经停止!");
188 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到视频流信息, 视频流可能已经停止"); 198 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到视频流信息, 视频流可能已经停止");
189 } 199 }
190 - MediaServerItem mediaInfo = mediaServerService.getOne(streamInfo.getMediaServerId()); 200 + MediaServerItem mediaInfo = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
191 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId); 201 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
192 if (!rtpInfo.getBoolean("exist")) { 202 if (!rtpInfo.getBoolean("exist")) {
193 logger.warn("视频转码API调用失败!, 视频流已停止推流!"); 203 logger.warn("视频转码API调用失败!, 视频流已停止推流!");
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
1 package com.genersoft.iot.vmp.vmanager.gb28181.playback; 1 package com.genersoft.iot.vmp.vmanager.gb28181.playback;
2 2
  3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
3 import com.genersoft.iot.vmp.common.StreamInfo; 5 import com.genersoft.iot.vmp.common.StreamInfo;
4 import com.genersoft.iot.vmp.conf.UserSetting; 6 import com.genersoft.iot.vmp.conf.UserSetting;
5 import com.genersoft.iot.vmp.conf.exception.ControllerException; 7 import com.genersoft.iot.vmp.conf.exception.ControllerException;
6 import com.genersoft.iot.vmp.conf.exception.ServiceException; 8 import com.genersoft.iot.vmp.conf.exception.ServiceException;
7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 9 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
  10 +import com.genersoft.iot.vmp.gb28181.bean.Device;
8 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 11 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
9 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 12 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  13 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
10 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 14 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
11 -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 15 +import com.genersoft.iot.vmp.service.IInviteStreamService;
12 import com.genersoft.iot.vmp.service.IPlayService; 16 import com.genersoft.iot.vmp.service.IPlayService;
  17 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
  18 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  19 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
13 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 20 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
14 import com.genersoft.iot.vmp.vmanager.bean.StreamContent; 21 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
15 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 22 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
@@ -20,17 +27,13 @@ import org.slf4j.Logger; @@ -20,17 +27,13 @@ import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory; 27 import org.slf4j.LoggerFactory;
21 import org.springframework.beans.factory.annotation.Autowired; 28 import org.springframework.beans.factory.annotation.Autowired;
22 import org.springframework.util.ObjectUtils; 29 import org.springframework.util.ObjectUtils;
23 -import org.springframework.web.bind.annotation.CrossOrigin;  
24 import org.springframework.web.bind.annotation.GetMapping; 30 import org.springframework.web.bind.annotation.GetMapping;
25 import org.springframework.web.bind.annotation.PathVariable; 31 import org.springframework.web.bind.annotation.PathVariable;
26 import org.springframework.web.bind.annotation.RequestMapping; 32 import org.springframework.web.bind.annotation.RequestMapping;
27 import org.springframework.web.bind.annotation.RestController; 33 import org.springframework.web.bind.annotation.RestController;
28 -  
29 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
30 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;  
31 -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;  
32 import org.springframework.web.context.request.async.DeferredResult; 34 import org.springframework.web.context.request.async.DeferredResult;
33 35
  36 +import javax.servlet.http.HttpServletRequest;
34 import javax.sip.InvalidArgumentException; 37 import javax.sip.InvalidArgumentException;
35 import javax.sip.SipException; 38 import javax.sip.SipException;
36 import java.text.ParseException; 39 import java.text.ParseException;
@@ -60,6 +63,9 @@ public class PlaybackController { @@ -60,6 +63,9 @@ public class PlaybackController {
60 private IRedisCatchStorage redisCatchStorage; 63 private IRedisCatchStorage redisCatchStorage;
61 64
62 @Autowired 65 @Autowired
  66 + private IInviteStreamService inviteStreamService;
  67 +
  68 + @Autowired
63 private IPlayService playService; 69 private IPlayService playService;
64 70
65 @Autowired 71 @Autowired
@@ -74,8 +80,8 @@ public class PlaybackController { @@ -74,8 +80,8 @@ public class PlaybackController {
74 @Parameter(name = "startTime", description = "开始时间", required = true) 80 @Parameter(name = "startTime", description = "开始时间", required = true)
75 @Parameter(name = "endTime", description = "结束时间", required = true) 81 @Parameter(name = "endTime", description = "结束时间", required = true)
76 @GetMapping("/start/{deviceId}/{channelId}") 82 @GetMapping("/start/{deviceId}/{channelId}")
77 - public DeferredResult<WVPResult<StreamContent>> start(@PathVariable String deviceId, @PathVariable String channelId,  
78 - String startTime, String endTime) { 83 + public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
  84 + String startTime, String endTime) {
79 85
80 if (logger.isDebugEnabled()) { 86 if (logger.isDebugEnabled()) {
81 logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); 87 logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
@@ -86,22 +92,31 @@ public class PlaybackController { @@ -86,22 +92,31 @@ public class PlaybackController {
86 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); 92 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
87 resultHolder.put(key, uuid, result); 93 resultHolder.put(key, uuid, result);
88 94
89 - WVPResult<StreamContent> wvpResult = new WVPResult<>();  
90 -  
91 - RequestMessage msg = new RequestMessage();  
92 - msg.setKey(key);  
93 - msg.setId(uuid);  
94 -  
95 - playService.playBack(deviceId, channelId, startTime, endTime, null,  
96 - playBackResult->{  
97 - wvpResult.setCode(playBackResult.getCode());  
98 - wvpResult.setMsg(playBackResult.getMsg());  
99 - if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {  
100 - StreamInfo streamInfo = (StreamInfo)playBackResult.getData();  
101 - wvpResult.setData(new StreamContent(streamInfo)); 95 + RequestMessage requestMessage = new RequestMessage();
  96 + requestMessage.setKey(key);
  97 + requestMessage.setId(uuid);
  98 +
  99 + playService.playBack(deviceId, channelId, startTime, endTime,
  100 + (code, msg, data)->{
  101 +
  102 + WVPResult<StreamContent> wvpResult = new WVPResult<>();
  103 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  104 + wvpResult.setCode(ErrorCode.SUCCESS.getCode());
  105 + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
  106 +
  107 + if (data != null) {
  108 + StreamInfo streamInfo = (StreamInfo)data;
  109 + if (userSetting.getUseSourceIpAsStreamIp()) {
  110 + streamInfo.channgeStreamIp(request.getLocalName());
  111 + }
  112 + wvpResult.setData(new StreamContent(streamInfo));
  113 + }
  114 + }else {
  115 + wvpResult.setCode(code);
  116 + wvpResult.setMsg(msg);
102 } 117 }
103 - msg.setData(wvpResult);  
104 - resultHolder.invokeResult(msg); 118 + requestMessage.setData(wvpResult);
  119 + resultHolder.invokeResult(requestMessage);
105 }); 120 });
106 121
107 return result; 122 return result;
@@ -169,14 +184,15 @@ public class PlaybackController { @@ -169,14 +184,15 @@ public class PlaybackController {
169 @GetMapping("/seek/{streamId}/{seekTime}") 184 @GetMapping("/seek/{streamId}/{seekTime}")
170 public void playSeek(@PathVariable String streamId, @PathVariable long seekTime) { 185 public void playSeek(@PathVariable String streamId, @PathVariable long seekTime) {
171 logger.info("playSeek: "+streamId+", "+seekTime); 186 logger.info("playSeek: "+streamId+", "+seekTime);
172 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
173 - if (null == streamInfo) { 187 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  188 +
  189 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
174 logger.warn("streamId不存在!"); 190 logger.warn("streamId不存在!");
175 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在"); 191 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
176 } 192 }
177 - Device device = storager.queryVideoDevice(streamInfo.getDeviceID()); 193 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
178 try { 194 try {
179 - cmder.playSeekCmd(device, streamInfo, seekTime); 195 + cmder.playSeekCmd(device, inviteInfo.getStreamInfo(), seekTime);
180 } catch (InvalidArgumentException | ParseException | SipException e) { 196 } catch (InvalidArgumentException | ParseException | SipException e) {
181 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage()); 197 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
182 } 198 }
@@ -188,8 +204,9 @@ public class PlaybackController { @@ -188,8 +204,9 @@ public class PlaybackController {
188 @GetMapping("/speed/{streamId}/{speed}") 204 @GetMapping("/speed/{streamId}/{speed}")
189 public void playSpeed(@PathVariable String streamId, @PathVariable Double speed) { 205 public void playSpeed(@PathVariable String streamId, @PathVariable Double speed) {
190 logger.info("playSpeed: "+streamId+", "+speed); 206 logger.info("playSpeed: "+streamId+", "+speed);
191 - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);  
192 - if (null == streamInfo) { 207 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  208 +
  209 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
193 logger.warn("streamId不存在!"); 210 logger.warn("streamId不存在!");
194 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在"); 211 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
195 } 212 }
@@ -197,9 +214,9 @@ public class PlaybackController { @@ -197,9 +214,9 @@ public class PlaybackController {
197 logger.warn("不支持的speed: " + speed); 214 logger.warn("不支持的speed: " + speed);
198 throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持的speed(0.25 0.5 1、2、4)"); 215 throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持的speed(0.25 0.5 1、2、4)");
199 } 216 }
200 - Device device = storager.queryVideoDevice(streamInfo.getDeviceID()); 217 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
201 try { 218 try {
202 - cmder.playSpeedCmd(device, streamInfo, speed); 219 + cmder.playSpeedCmd(device, inviteInfo.getStreamInfo(), speed);
203 } catch (InvalidArgumentException | ParseException | SipException e) { 220 } catch (InvalidArgumentException | ParseException | SipException e) {
204 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage()); 221 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
205 } 222 }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
1 package com.genersoft.iot.vmp.vmanager.gb28181.record; 1 package com.genersoft.iot.vmp.vmanager.gb28181.record;
2 2
3 import com.genersoft.iot.vmp.common.StreamInfo; 3 import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.conf.UserSetting;
4 import com.genersoft.iot.vmp.conf.exception.ControllerException; 5 import com.genersoft.iot.vmp.conf.exception.ControllerException;
5 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 6 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
6 import com.genersoft.iot.vmp.gb28181.bean.Device; 7 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; @@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
11 import com.genersoft.iot.vmp.service.IDeviceService; 12 import com.genersoft.iot.vmp.service.IDeviceService;
12 import com.genersoft.iot.vmp.service.IPlayService; 13 import com.genersoft.iot.vmp.service.IPlayService;
  14 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
13 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 15 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
14 import com.genersoft.iot.vmp.utils.DateUtil; 16 import com.genersoft.iot.vmp.utils.DateUtil;
15 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 17 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
@@ -27,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping; @@ -27,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
27 import org.springframework.web.bind.annotation.RestController; 29 import org.springframework.web.bind.annotation.RestController;
28 import org.springframework.web.context.request.async.DeferredResult; 30 import org.springframework.web.context.request.async.DeferredResult;
29 31
  32 +import javax.servlet.http.HttpServletRequest;
30 import javax.sip.InvalidArgumentException; 33 import javax.sip.InvalidArgumentException;
31 import javax.sip.SipException; 34 import javax.sip.SipException;
32 import java.text.ParseException; 35 import java.text.ParseException;
@@ -55,8 +58,8 @@ public class GBRecordController { @@ -55,8 +58,8 @@ public class GBRecordController {
55 @Autowired 58 @Autowired
56 private IDeviceService deviceService; 59 private IDeviceService deviceService;
57 60
58 -  
59 - 61 + @Autowired
  62 + private UserSetting userSetting;
60 63
61 @Operation(summary = "录像查询") 64 @Operation(summary = "录像查询")
62 @Parameter(name = "deviceId", description = "设备国标编号", required = true) 65 @Parameter(name = "deviceId", description = "设备国标编号", required = true)
@@ -119,8 +122,8 @@ public class GBRecordController { @@ -119,8 +122,8 @@ public class GBRecordController {
119 @Parameter(name = "endTime", description = "结束时间", required = true) 122 @Parameter(name = "endTime", description = "结束时间", required = true)
120 @Parameter(name = "downloadSpeed", description = "下载倍速", required = true) 123 @Parameter(name = "downloadSpeed", description = "下载倍速", required = true)
121 @GetMapping("/download/start/{deviceId}/{channelId}") 124 @GetMapping("/download/start/{deviceId}/{channelId}")
122 - public DeferredResult<WVPResult<StreamContent>> download(@PathVariable String deviceId, @PathVariable String channelId,  
123 - String startTime, String endTime, String downloadSpeed) { 125 + public DeferredResult<WVPResult<StreamContent>> download(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
  126 + String startTime, String endTime, String downloadSpeed) {
124 127
125 if (logger.isDebugEnabled()) { 128 if (logger.isDebugEnabled()) {
126 logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed)); 129 logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed));
@@ -130,22 +133,32 @@ public class GBRecordController { @@ -130,22 +133,32 @@ public class GBRecordController {
130 String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId; 133 String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
131 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(30000L); 134 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(30000L);
132 resultHolder.put(key, uuid, result); 135 resultHolder.put(key, uuid, result);
133 - RequestMessage msg = new RequestMessage();  
134 - msg.setId(uuid);  
135 - msg.setKey(key);  
136 -  
137 - WVPResult<StreamContent> wvpResult = new WVPResult<>();  
138 -  
139 - playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, playBackResult->{  
140 -  
141 - wvpResult.setCode(playBackResult.getCode());  
142 - wvpResult.setMsg(playBackResult.getMsg());  
143 - if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {  
144 - StreamInfo streamInfo = (StreamInfo)playBackResult.getData();  
145 - wvpResult.setData(new StreamContent(streamInfo)); 136 + RequestMessage requestMessage = new RequestMessage();
  137 + requestMessage.setId(uuid);
  138 + requestMessage.setKey(key);
  139 +
  140 +
  141 + playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed),
  142 + (code, msg, data)->{
  143 +
  144 + WVPResult<StreamContent> wvpResult = new WVPResult<>();
  145 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  146 + wvpResult.setCode(ErrorCode.SUCCESS.getCode());
  147 + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
  148 +
  149 + if (data != null) {
  150 + StreamInfo streamInfo = (StreamInfo)data;
  151 + if (userSetting.getUseSourceIpAsStreamIp()) {
  152 + streamInfo.channgeStreamIp(request.getLocalName());
  153 + }
  154 + wvpResult.setData(new StreamContent(streamInfo));
  155 + }
  156 + }else {
  157 + wvpResult.setCode(code);
  158 + wvpResult.setMsg(msg);
146 } 159 }
147 - msg.setData(wvpResult);  
148 - resultHolder.invokeResult(msg); 160 + requestMessage.setData(wvpResult);
  161 + resultHolder.invokeResult(requestMessage);
149 }); 162 });
150 163
151 return result; 164 return result;
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
@@ -57,7 +57,7 @@ public class UserController { @@ -57,7 +57,7 @@ public class UserController {
57 if (user == null) { 57 if (user == null) {
58 throw new ControllerException(ErrorCode.ERROR100.getCode(), "用户名或密码错误"); 58 throw new ControllerException(ErrorCode.ERROR100.getCode(), "用户名或密码错误");
59 }else { 59 }else {
60 - String jwt = JwtUtils.createToken(username, password); 60 + String jwt = JwtUtils.createToken(username, password, user.getRole().getId());
61 response.setHeader(JwtUtils.getHeader(), jwt); 61 response.setHeader(JwtUtils.getHeader(), jwt);
62 user.setAccessToken(jwt); 62 user.setAccessToken(jwt);
63 } 63 }
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
1 package com.genersoft.iot.vmp.web.gb28181; 1 package com.genersoft.iot.vmp.web.gb28181;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
4 -import com.genersoft.iot.vmp.common.StreamInfo; 4 +import com.genersoft.iot.vmp.common.InviteInfo;
  5 +import com.genersoft.iot.vmp.common.InviteSessionType;
5 import com.genersoft.iot.vmp.conf.UserSetting; 6 import com.genersoft.iot.vmp.conf.UserSetting;
6 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
7 import com.genersoft.iot.vmp.gb28181.bean.Device; 8 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -9,13 +10,18 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; @@ -9,13 +10,18 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
9 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
10 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
11 import com.genersoft.iot.vmp.service.IDeviceService; 12 import com.genersoft.iot.vmp.service.IDeviceService;
  13 +import com.genersoft.iot.vmp.service.IInviteStreamService;
12 import com.genersoft.iot.vmp.service.IPlayService; 14 import com.genersoft.iot.vmp.service.IPlayService;
  15 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
13 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
14 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 17 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
15 import org.slf4j.Logger; 18 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory; 19 import org.slf4j.LoggerFactory;
17 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
18 -import org.springframework.web.bind.annotation.*; 21 +import org.springframework.web.bind.annotation.RequestMapping;
  22 +import org.springframework.web.bind.annotation.RequestParam;
  23 +import org.springframework.web.bind.annotation.ResponseBody;
  24 +import org.springframework.web.bind.annotation.RestController;
19 import org.springframework.web.context.request.async.DeferredResult; 25 import org.springframework.web.context.request.async.DeferredResult;
20 26
21 import javax.sip.InvalidArgumentException; 27 import javax.sip.InvalidArgumentException;
@@ -46,6 +52,9 @@ public class ApiStreamController { @@ -46,6 +52,9 @@ public class ApiStreamController {
46 private IRedisCatchStorage redisCatchStorage; 52 private IRedisCatchStorage redisCatchStorage;
47 53
48 @Autowired 54 @Autowired
  55 + private IInviteStreamService inviteStreamService;
  56 +
  57 + @Autowired
49 private IDeviceService deviceService; 58 private IDeviceService deviceService;
50 59
51 @Autowired 60 @Autowired
@@ -111,46 +120,53 @@ public class ApiStreamController { @@ -111,46 +120,53 @@ public class ApiStreamController {
111 return resultDeferredResult; 120 return resultDeferredResult;
112 } 121 }
113 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device); 122 MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
114 - playService.play(newMediaServerItem, serial, code, (mediaServerItem, response)->{  
115 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(serial, code);  
116 - JSONObject result = new JSONObject();  
117 - result.put("StreamID", streamInfo.getStream());  
118 - result.put("DeviceID", device.getDeviceId());  
119 - result.put("ChannelID", code);  
120 - result.put("ChannelName", deviceChannel.getName());  
121 - result.put("ChannelCustomName", "");  
122 - result.put("FLV", streamInfo.getFlv().getUrl());  
123 - result.put("WS_FLV", streamInfo.getWs_flv().getUrl());  
124 - result.put("RTMP", streamInfo.getRtmp().getUrl());  
125 - result.put("HLS", streamInfo.getHls().getUrl());  
126 - result.put("RTSP", streamInfo.getRtsp().getUrl());  
127 - result.put("WEBRTC", streamInfo.getRtc().getUrl());  
128 - result.put("CDN", "");  
129 - result.put("SnapURL", "");  
130 - result.put("Transport", device.getTransport());  
131 - result.put("StartAt", "");  
132 - result.put("Duration", "");  
133 - result.put("SourceVideoCodecName", "");  
134 - result.put("SourceVideoWidth", "");  
135 - result.put("SourceVideoHeight", "");  
136 - result.put("SourceVideoFrameRate", "");  
137 - result.put("SourceAudioCodecName", "");  
138 - result.put("SourceAudioSampleRate", "");  
139 - result.put("AudioEnable", "");  
140 - result.put("Ondemand", "");  
141 - result.put("InBytes", "");  
142 - result.put("InBitRate", "");  
143 - result.put("OutBytes", "");  
144 - result.put("NumOutputs", "");  
145 - result.put("CascadeSize", "");  
146 - result.put("RelaySize", "");  
147 - result.put("ChannelPTZType", "0");  
148 - resultDeferredResult.setResult(result);  
149 - }, (eventResult) -> {  
150 - JSONObject result = new JSONObject();  
151 - result.put("error", "channel[ " + code + " ] " + eventResult.msg);  
152 - resultDeferredResult.setResult(result);  
153 - }, null); 123 +
  124 +
  125 + playService.play(newMediaServerItem, serial, code, (errorCode, msg, data) -> {
  126 + if (errorCode == InviteErrorCode.SUCCESS.getCode()) {
  127 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, serial, code);
  128 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  129 + JSONObject result = new JSONObject();
  130 + result.put("StreamID", inviteInfo.getStreamInfo().getStream());
  131 + result.put("DeviceID", device.getDeviceId());
  132 + result.put("ChannelID", code);
  133 + result.put("ChannelName", deviceChannel.getName());
  134 + result.put("ChannelCustomName", "");
  135 + result.put("FLV", inviteInfo.getStreamInfo().getFlv().getUrl());
  136 + result.put("WS_FLV", inviteInfo.getStreamInfo().getWs_flv().getUrl());
  137 + result.put("RTMP", inviteInfo.getStreamInfo().getRtmp().getUrl());
  138 + result.put("HLS", inviteInfo.getStreamInfo().getHls().getUrl());
  139 + result.put("RTSP", inviteInfo.getStreamInfo().getRtsp().getUrl());
  140 + result.put("WEBRTC", inviteInfo.getStreamInfo().getRtc().getUrl());
  141 + result.put("CDN", "");
  142 + result.put("SnapURL", "");
  143 + result.put("Transport", device.getTransport());
  144 + result.put("StartAt", "");
  145 + result.put("Duration", "");
  146 + result.put("SourceVideoCodecName", "");
  147 + result.put("SourceVideoWidth", "");
  148 + result.put("SourceVideoHeight", "");
  149 + result.put("SourceVideoFrameRate", "");
  150 + result.put("SourceAudioCodecName", "");
  151 + result.put("SourceAudioSampleRate", "");
  152 + result.put("AudioEnable", "");
  153 + result.put("Ondemand", "");
  154 + result.put("InBytes", "");
  155 + result.put("InBitRate", "");
  156 + result.put("OutBytes", "");
  157 + result.put("NumOutputs", "");
  158 + result.put("CascadeSize", "");
  159 + result.put("RelaySize", "");
  160 + result.put("ChannelPTZType", "0");
  161 + resultDeferredResult.setResult(result);
  162 + }
  163 + }else {
  164 + JSONObject result = new JSONObject();
  165 + result.put("error", "channel[ " + code + " ] " + msg);
  166 + resultDeferredResult.setResult(result);
  167 + }
  168 + });
  169 +
154 return resultDeferredResult; 170 return resultDeferredResult;
155 } 171 }
156 172
@@ -171,8 +187,8 @@ public class ApiStreamController { @@ -171,8 +187,8 @@ public class ApiStreamController {
171 187
172 ){ 188 ){
173 189
174 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(serial, code);  
175 - if (streamInfo == null) { 190 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, serial, code);
  191 + if (inviteInfo == null) {
176 JSONObject result = new JSONObject(); 192 JSONObject result = new JSONObject();
177 result.put("error","未找到流信息"); 193 result.put("error","未找到流信息");
178 return result; 194 return result;
@@ -184,14 +200,14 @@ public class ApiStreamController { @@ -184,14 +200,14 @@ public class ApiStreamController {
184 return result; 200 return result;
185 } 201 }
186 try { 202 try {
187 - cmder.streamByeCmd(device, code, streamInfo.getStream(), null);  
188 - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { 203 + cmder.streamByeCmd(device, code, inviteInfo.getStream(), null);
  204 + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
189 JSONObject result = new JSONObject(); 205 JSONObject result = new JSONObject();
190 result.put("error","发送BYE失败:" + e.getMessage()); 206 result.put("error","发送BYE失败:" + e.getMessage());
191 return result; 207 return result;
192 } 208 }
193 - redisCatchStorage.stopPlay(streamInfo);  
194 - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 209 + inviteStreamService.removeInviteInfo(inviteInfo);
  210 + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
195 return null; 211 return null;
196 } 212 }
197 213
src/main/resources/all-application.yml
@@ -65,8 +65,11 @@ server: @@ -65,8 +65,11 @@ server:
65 65
66 # 作为28181服务器的配置 66 # 作为28181服务器的配置
67 sip: 67 sip:
68 - # [必须修改] 本机的IP  
69 - ip: 192.168.0.100 68 + # [必须修改] 本机的IP,对应你的网卡,监听什么ip就是使用什么网卡,
  69 + # 如果要监听多张网卡,可以使用逗号分隔多个IP, 例如: 192.168.1.4,10.0.0.4
  70 + # 如果不明白,就使用0.0.0.0,大部分情况都是可以的
  71 + # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。
  72 + ip: 0.0.0.0
70 # [可选] 没有任何业务需求,仅仅是在前端展示的时候用 73 # [可选] 没有任何业务需求,仅仅是在前端展示的时候用
71 show-ip: 192.168.0.100 74 show-ip: 192.168.0.100
72 # [可选] 28181服务监听的端口 75 # [可选] 28181服务监听的端口
@@ -89,6 +92,15 @@ sip: @@ -89,6 +92,15 @@ sip:
89 # 是否存储alarm信息 92 # 是否存储alarm信息
90 alarm: false 93 alarm: false
91 94
  95 +# 做为JT1078服务器的配置
  96 +jt1078:
  97 + #[必须修改] 是否开启1078的服务
  98 + enable: true
  99 + #[必修修改] 1708设备接入的端口
  100 + port: 21078
  101 + #[可选] 设备鉴权的密码
  102 + password: admin123
  103 +
92 #zlm 默认服务器配置 104 #zlm 默认服务器配置
93 media: 105 media:
94 # [必须修改] zlm服务器唯一id,用于触发hook时区别是哪台服务器,general.mediaServerId 106 # [必须修改] zlm服务器唯一id,用于触发hook时区别是哪台服务器,general.mediaServerId
@@ -182,6 +194,12 @@ user-settings: @@ -182,6 +194,12 @@ user-settings:
182 send-to-platforms-when-id-lost: true 194 send-to-platforms-when-id-lost: true
183 # 保持通道状态,不接受notify通道状态变化, 兼容海康平台发送错误消息 195 # 保持通道状态,不接受notify通道状态变化, 兼容海康平台发送错误消息
184 refuse-channel-status-channel-form-notify: false 196 refuse-channel-status-channel-form-notify: false
  197 + # 设置notify缓存队列最大长度,超过此长度的数据将返回486 BUSY_HERE,消息丢弃, 默认10000
  198 + max-notify-count-queue: 10000
  199 + # 设备/通道状态变化时发送消息
  200 + device-status-notify: false
  201 + # 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式
  202 + use-custom-ssrc-for-parent-invite: true
185 # 跨域配置,配置你访问前端页面的地址即可, 可以配置多个 203 # 跨域配置,配置你访问前端页面的地址即可, 可以配置多个
186 allowed-origins: 204 allowed-origins:
187 - http://localhost:8008 205 - http://localhost:8008
src/main/resources/application-dev.yml
@@ -18,29 +18,19 @@ spring: @@ -18,29 +18,19 @@ spring:
18 timeout: 10000 18 timeout: 10000
19 # mysql数据源 19 # mysql数据源
20 datasource: 20 datasource:
21 - type: com.alibaba.druid.pool.DruidDataSource 21 + type: com.zaxxer.hikari.HikariDataSource
22 driver-class-name: com.mysql.cj.jdbc.Driver 22 driver-class-name: com.mysql.cj.jdbc.Driver
23 url: jdbc:mysql://127.0.0.1:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true 23 url: jdbc:mysql://127.0.0.1:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
24 username: root 24 username: root
25 password: 123456 25 password: 123456
26 - druid: 26 + hikari:
  27 + connection-timeout: 20000 # 是客户端等待连接池连接的最大毫秒数
27 initialSize: 10 # 连接池初始化连接数 28 initialSize: 10 # 连接池初始化连接数
28 - maxActive: 200 # 连接池最大连接数  
29 - minIdle: 5 # 连接池最小空闲连接数  
30 - maxWait: 60000 # 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。  
31 - keepAlive: true # 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作。  
32 - validationQuery: select 1 # 检测连接是否有效sql,要求是查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。  
33 - testWhileIdle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。  
34 - testOnBorrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。  
35 - testOnReturn: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。  
36 - poolPreparedStatements: false # 是否開啟PSCache,並且指定每個連線上PSCache的大小  
37 - timeBetweenEvictionRunsMillis: 60000 # 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位是毫秒  
38 - minEvictableIdleTimeMillis: 300000 # 配置一個連線在池中最小生存的時間,單位是毫秒  
39 - filters: stat,slf4j # 配置监控统计拦截的filters,监控统计用的filter:sta, 日志用的filter:log4j  
40 - useGlobalDataSourceStat: true # 合并多个DruidDataSource的监控数据  
41 - # 通过connectProperties属性来打开mergeSql功能;慢SQL记录  
42 - connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=1000  
43 - #stat-view-servlet.url-pattern: /admin/druid/* 29 + maximum-pool-size: 200 # 连接池最大连接数
  30 + minimum-idle: 5 # 连接池最小空闲连接数
  31 + idle-timeout: 300000 # 允许连接在连接池中空闲的最长时间(以毫秒为单位)
  32 + max-lifetime: 1200000 # 是池中连接关闭后的最长生命周期(以毫秒为单位)
  33 +
44 34
45 #[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 35 #[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
46 server: 36 server:
@@ -48,7 +38,10 @@ server: @@ -48,7 +38,10 @@ server:
48 38
49 # 作为28181服务器的配置 39 # 作为28181服务器的配置
50 sip: 40 sip:
51 - # [必须修改] 本机的IP 41 + # [必须修改] 本机的IP,对应你的网卡,监听什么ip就是使用什么网卡,
  42 + # 如果要监听多张网卡,可以使用逗号分隔多个IP, 例如: 192.168.1.4,10.0.0.4
  43 + # 如果不明白,就使用0.0.0.0,大部分情况都是可以的
  44 + # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。
52 ip: 192.168.41.16 45 ip: 192.168.41.16
53 # [可选] 28181服务监听的端口 46 # [可选] 28181服务监听的端口
54 port: 5060 47 port: 5060
src/main/resources/application-docker.yml
@@ -23,7 +23,7 @@ spring: @@ -23,7 +23,7 @@ spring:
23 url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true&useSSL=false&allowMultiQueries=true 23 url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true&useSSL=false&allowMultiQueries=true
24 username: root 24 username: root
25 password: root 25 password: root
26 - type: com.alibaba.druid.pool.DruidDataSource 26 + type: com.zaxxer.hikari.HikariDataSource
27 driver-class-name: com.mysql.cj.jdbc.Driver 27 driver-class-name: com.mysql.cj.jdbc.Driver
28 28
29 # [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 29 # [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
@@ -32,7 +32,10 @@ server: @@ -32,7 +32,10 @@ server:
32 32
33 # 作为28181服务器的配置 33 # 作为28181服务器的配置
34 sip: 34 sip:
35 - # [必须修改] 本机的IP 35 + # [必须修改] 本机的IP,对应你的网卡,监听什么ip就是使用什么网卡,
  36 + # 如果要监听多张网卡,可以使用逗号分隔多个IP, 例如: 192.168.1.4,10.0.0.4
  37 + # 如果不明白,就使用0.0.0.0,大部分情况都是可以的
  38 + # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。
36 ip: ${WVP_HOST:127.0.0.1} 39 ip: ${WVP_HOST:127.0.0.1}
37 # [可选] 28181服务监听的端口 40 # [可选] 28181服务监听的端口
38 port: ${WVP_PORT:5060} 41 port: ${WVP_PORT:5060}
src/main/resources/application.yml
@@ -2,5 +2,4 @@ spring: @@ -2,5 +2,4 @@ spring:
2 application: 2 application:
3 name: wvp 3 name: wvp
4 profiles: 4 profiles:
5 - active: local  
6 - include: device-compatible  
7 \ No newline at end of file 5 \ No newline at end of file
  6 + active: local
8 \ No newline at end of file 7 \ No newline at end of file
src/test/java/com/genersoft/iot/vmp/jt1078/JT1078ServerTest.java 0 → 100644
  1 +package com.genersoft.iot.vmp.jt1078;
  2 +
  3 +import com.genersoft.iot.vmp.jt1078.cmd.JT1078Template;
  4 +import com.genersoft.iot.vmp.jt1078.codec.netty.TcpServer;
  5 +import com.genersoft.iot.vmp.jt1078.proc.response.J9102;
  6 +import com.genersoft.iot.vmp.jt1078.proc.response.J9201;
  7 +import com.genersoft.iot.vmp.jt1078.proc.response.J9202;
  8 +import com.genersoft.iot.vmp.jt1078.proc.response.J9205;
  9 +
  10 +import java.util.Scanner;
  11 +
  12 +/**
  13 + * @author QingtaiJiang
  14 + * @date 2023/4/28 14:22
  15 + * @email qingtaij@163.com
  16 + */
  17 +public class JT1078ServerTest {
  18 +
  19 + private static final JT1078Template jt1078Template = new JT1078Template();
  20 +
  21 + public static void main(String[] args) {
  22 + System.out.println("Starting jt1078 server...");
  23 + TcpServer tcpServer = new TcpServer(21078);
  24 + tcpServer.start();
  25 + System.out.println("Start jt1078 server success!");
  26 +
  27 +
  28 + Scanner s = new Scanner(System.in);
  29 + while (true) {
  30 + String code = s.nextLine();
  31 + switch (code) {
  32 + case "1":
  33 + test9102();
  34 + break;
  35 + case "2":
  36 + test9201();
  37 + break;
  38 + case "3":
  39 + test9202();
  40 + break;
  41 + case "4":
  42 + test9205();
  43 + break;
  44 + default:
  45 + break;
  46 + }
  47 + }
  48 + }
  49 +
  50 + private static void test9102() {
  51 + J9102 j9102 = new J9102();
  52 + j9102.setChannel(1);
  53 + j9102.setCommand(0);
  54 + j9102.setCloseType(0);
  55 + j9102.setStreamType(0);
  56 +
  57 + String s = jt1078Template.stopLive("18864197066", j9102, 6);
  58 + System.out.println(s);
  59 + }
  60 +
  61 + private static void test9201() {
  62 + J9201 j9201 = new J9201();
  63 + j9201.setIp("192.168.1.1");
  64 + j9201.setChannel(1);
  65 + j9201.setTcpPort(7618);
  66 + j9201.setUdpPort(7618);
  67 + j9201.setType(0);
  68 + j9201.setRate(0);
  69 + j9201.setStorageType(0);
  70 + j9201.setPlaybackType(0);
  71 + j9201.setPlaybackSpeed(0);
  72 + j9201.setStartTime("230428134100");
  73 + j9201.setEndTime("230428134200");
  74 +
  75 + String s = jt1078Template.startBackLive("18864197066", j9201, 6);
  76 + System.out.println(s);
  77 + }
  78 +
  79 + private static void test9202() {
  80 + J9202 j9202 = new J9202();
  81 +
  82 + j9202.setChannel(1);
  83 + j9202.setPlaybackType(2);
  84 + j9202.setPlaybackSpeed(0);
  85 + j9202.setPlaybackTime("230428134100");
  86 +
  87 + String s = jt1078Template.controlBackLive("18864197066", j9202, 6);
  88 + System.out.println(s);
  89 + }
  90 +
  91 + private static void test9205() {
  92 + J9205 j9205 = new J9205();
  93 + j9205.setChannelId(1);
  94 + j9205.setStartTime("230428134100");
  95 + j9205.setEndTime("230428134100");
  96 + j9205.setMediaType(0);
  97 + j9205.setStreamType(0);
  98 + j9205.setStorageType(0);
  99 +
  100 + String s = jt1078Template.queryBackTime("18864197066", j9205, 6);
  101 + System.out.println(s);
  102 + }
  103 +}
web_src/src/components/DeviceList.vue
@@ -25,11 +25,13 @@ @@ -25,11 +25,13 @@
25 </el-table-column> 25 </el-table-column>
26 <el-table-column prop="manufacturer" label="厂家" min-width="120" > 26 <el-table-column prop="manufacturer" label="厂家" min-width="120" >
27 </el-table-column> 27 </el-table-column>
  28 + <el-table-column prop="transport" label="信令传输模式" min-width="120" >
  29 + </el-table-column>
28 <el-table-column label="流传输模式" min-width="160" > 30 <el-table-column label="流传输模式" min-width="160" >
29 <template slot-scope="scope"> 31 <template slot-scope="scope">
30 <el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择" style="width: 120px"> 32 <el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择" style="width: 120px">
31 <el-option key="UDP" label="UDP" value="UDP"></el-option> 33 <el-option key="UDP" label="UDP" value="UDP"></el-option>
32 - <el-option key="TCP-ACTIVE" label="TCP主动模式" :disabled="true" value="TCP-ACTIVE"></el-option> 34 + <el-option key="TCP-ACTIVE" label="TCP主动模式" value="TCP-ACTIVE"></el-option>
33 <el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option> 35 <el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option>
34 </el-select> 36 </el-select>
35 </template> 37 </template>
web_src/src/components/GBRecordDetail.vue
@@ -182,9 +182,11 @@ @@ -182,9 +182,11 @@
182 this.playerStyle["height"] = this.winHeight + "px"; 182 this.playerStyle["height"] = this.winHeight + "px";
183 this.chooseDate = moment().format('YYYY-MM-DD') 183 this.chooseDate = moment().format('YYYY-MM-DD')
184 this.dateChange(); 184 this.dateChange();
  185 + window.addEventListener('beforeunload', this.stopPlayRecord)
185 }, 186 },
186 destroyed() { 187 destroyed() {
187 this.$destroy('recordVideoPlayer'); 188 this.$destroy('recordVideoPlayer');
  189 + window.removeEventListener('beforeunload', this.stopPlayRecord)
188 }, 190 },
189 methods: { 191 methods: {
190 dateChange(){ 192 dateChange(){
@@ -338,14 +340,18 @@ @@ -338,14 +340,18 @@
338 }); 340 });
339 }, 341 },
340 stopPlayRecord: function (callback) { 342 stopPlayRecord: function (callback) {
341 - this.$refs["recordVideoPlayer"].pause();  
342 - this.videoUrl = '';  
343 - this.$axios({  
344 - method: 'get',  
345 - url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId  
346 - }).then(function (res) {  
347 - if (callback) callback()  
348 - }); 343 + console.log("停止录像回放")
  344 + if (this.streamId !== "") {
  345 + this.$refs["recordVideoPlayer"].pause();
  346 + this.videoUrl = '';
  347 + this.$axios({
  348 + method: 'get',
  349 + url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId
  350 + }).then(function (res) {
  351 + if (callback) callback()
  352 + });
  353 + }
  354 +
349 }, 355 },
350 getDataWidth(item){ 356 getDataWidth(item){
351 let timeForFile = this.getTimeForFile(item); 357 let timeForFile = this.getTimeForFile(item);
@@ -423,8 +429,14 @@ @@ -423,8 +429,14 @@
423 return hStr + ":" + mStr + ":" + sStr 429 return hStr + ":" + mStr + ":" + sStr
424 }, 430 },
425 goBack(){ 431 goBack(){
  432 + // 如果正在进行录像回放则,发送停止
  433 + if (this.streamId !== "") {
  434 + this.stopPlayRecord(()=> {
  435 + this.streamId = "";
  436 + })
  437 + }
426 window.history.go(-1); 438 window.history.go(-1);
427 - } 439 + },
428 } 440 }
429 }; 441 };
430 </script> 442 </script>
web_src/src/components/channelList.vue
@@ -123,7 +123,6 @@ @@ -123,7 +123,6 @@
123 <script> 123 <script>
124 import devicePlayer from './dialog/devicePlayer.vue' 124 import devicePlayer from './dialog/devicePlayer.vue'
125 import uiHeader from '../layout/UiHeader.vue' 125 import uiHeader from '../layout/UiHeader.vue'
126 -import moment from "moment";  
127 import DeviceService from "./service/DeviceService"; 126 import DeviceService from "./service/DeviceService";
128 import DeviceTree from "./common/DeviceTree"; 127 import DeviceTree from "./common/DeviceTree";
129 128
@@ -290,8 +289,8 @@ export default { @@ -290,8 +289,8 @@ export default {
290 }); 289 });
291 }, 290 },
292 getSnap: function (row) { 291 getSnap: function (row) {
293 - let url = (process.env.NODE_ENV === 'development'? "debug": "") + '/api/device/query/snap/' + row.deviceId + '/' + row.channelId  
294 - return url 292 + let baseUrl = window.baseUrl ? window.baseUrl : "";
  293 + return ((process.env.NODE_ENV === 'development') ? process.env.BASE_API : baseUrl) + '/api/device/query/snap/' + row.deviceId + '/' + row.channelId;
295 }, 294 },
296 getBigSnap: function (row) { 295 getBigSnap: function (row) {
297 return [this.getSnap(row)] 296 return [this.getSnap(row)]
web_src/src/components/dialog/recordDownload.vue
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 </el-col> 7 </el-col>
8 <el-col :span="6" > 8 <el-col :span="6" >
9 <el-button icon="el-icon-download" v-if="percentage < 100" size="mini" title="点击下载可将以缓存部分下载到本地" @click="download()">停止缓存并下载</el-button> 9 <el-button icon="el-icon-download" v-if="percentage < 100" size="mini" title="点击下载可将以缓存部分下载到本地" @click="download()">停止缓存并下载</el-button>
  10 + <el-button icon="el-icon-download" v-if="downloadFile" size="mini" title="点击下载" @click="downloadFileClientEvent()">点击下载</el-button>
10 </el-col> 11 </el-col>
11 </el-row> 12 </el-row>
12 </el-dialog> 13 </el-dialog>
@@ -21,7 +22,7 @@ import moment from &quot;moment&quot;; @@ -21,7 +22,7 @@ import moment from &quot;moment&quot;;
21 export default { 22 export default {
22 name: 'recordDownload', 23 name: 'recordDownload',
23 created() { 24 created() {
24 - 25 + window.addEventListener('beforeunload', this.stopDownloadRecord)
25 26
26 }, 27 },
27 data() { 28 data() {
@@ -39,7 +40,8 @@ export default { @@ -39,7 +40,8 @@ export default {
39 taskId: null, 40 taskId: null,
40 getProgressRun: false, 41 getProgressRun: false,
41 getProgressForFileRun: false, 42 getProgressForFileRun: false,
42 - timer: null 43 + timer: null,
  44 + downloadFile: null,
43 45
44 }; 46 };
45 }, 47 },
@@ -96,7 +98,10 @@ export default { @@ -96,7 +98,10 @@ export default {
96 }); 98 });
97 }, 99 },
98 close: function (){ 100 close: function (){
99 - this.stopDownloadRecord(); 101 + if (this.streamInfo.progress < 1) {
  102 + this.stopDownloadRecord();
  103 + }
  104 +
100 if (this.timer !== null) { 105 if (this.timer !== null) {
101 window.clearTimeout(this.timer); 106 window.clearTimeout(this.timer);
102 this.timer = null; 107 this.timer = null;
@@ -158,7 +163,7 @@ export default { @@ -158,7 +163,7 @@ export default {
158 } 163 }
159 setTimeout( ()=>{ 164 setTimeout( ()=>{
160 if (!this.showDialog) return; 165 if (!this.showDialog) return;
161 - this.getProgressForFile(this.getProgressForFileTimer()) 166 + this.getProgressForFile(this.getProgressForFileTimer)
162 }, 1000) 167 }, 1000)
163 }, 168 },
164 getProgressForFile: function (callback){ 169 getProgressForFile: function (callback){
@@ -176,13 +181,17 @@ export default { @@ -176,13 +181,17 @@ export default {
176 if (res.data.code === 0) { 181 if (res.data.code === 0) {
177 if (res.data.data.length === 0){ 182 if (res.data.data.length === 0){
178 this.percentage = 0 183 this.percentage = 0
  184 + // 往往在多次请求后(实验五分钟的视频是三次请求),才会返回数据,第一次请求通常是返回空数组
  185 + if (callback)callback()
179 return 186 return
180 } 187 }
181 - this.percentage = parseFloat(res.data.data.percentage)*100 188 + // res.data.data应是数组类型
  189 + this.percentage = parseFloat(res.data.data[0].percentage)*100
182 if (res.data.data[0].percentage === '1') { 190 if (res.data.data[0].percentage === '1') {
183 this.getProgressForFileRun = false; 191 this.getProgressForFileRun = false;
184 - window.open(res.data.data[0].downloadFile)  
185 - this.close(); 192 + this.downloadFile = res.data.data[0].downloadFile
  193 + this.title = "文件处理完成,点击按扭下载"
  194 + // window.open(res.data.data[0].downloadFile)
186 }else { 195 }else {
187 if (callback)callback() 196 if (callback)callback()
188 } 197 }
@@ -190,7 +199,13 @@ export default { @@ -190,7 +199,13 @@ export default {
190 }).catch(function (error) { 199 }).catch(function (error) {
191 console.log(error); 200 console.log(error);
192 }); 201 });
193 - } 202 + },
  203 + downloadFileClientEvent: function (){
  204 + window.open(this.downloadFile )
  205 + }
  206 + },
  207 + destroyed() {
  208 + window.removeEventListener('beforeunload', this.stopDownloadRecord)
194 } 209 }
195 }; 210 };
196 </script> 211 </script>
web_src/src/layout/UiHeader.vue
@@ -40,6 +40,7 @@ @@ -40,6 +40,7 @@
40 40
41 import changePasswordDialog from '../components/dialog/changePassword.vue' 41 import changePasswordDialog from '../components/dialog/changePassword.vue'
42 import userService from '../components/service/UserService' 42 import userService from '../components/service/UserService'
  43 +import {Notification} from 'element-ui';
43 44
44 export default { 45 export default {
45 name: "UiHeader", 46 name: "UiHeader",