Commit 23bd11869bbad6a111d7ee434b87e2e775bce953

Authored by mk1990
1 parent c239ee27

添加国标级联录像控制功能

src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
1   -package com.genersoft.iot.vmp.gb28181.transmit.cmd;
2   -
3   -import com.genersoft.iot.vmp.common.StreamInfo;
4   -import com.genersoft.iot.vmp.gb28181.bean.*;
5   -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6   -import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
7   -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
8   -import com.genersoft.iot.vmp.service.bean.SSRCInfo;
9   -
10   -import javax.sip.Dialog;
11   -
12   -/**
13   - * @description:设备能力接口,用于定义设备的控制、查询能力
14   - * @author: swwheihei
15   - * @date: 2020年5月3日 下午9:16:34
16   - */
17   -public interface ISIPCommander {
18   -
19   - /**
20   - * 云台方向放控制,使用配置文件中的默认镜头移动速度
21   - *
22   - * @param device 控制设备
23   - * @param channelId 预览通道
24   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
25   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
26   - */
27   - boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown);
28   -
29   - /**
30   - * 云台方向放控制
31   - *
32   - * @param device 控制设备
33   - * @param channelId 预览通道
34   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
35   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
36   - * @param moveSpeed 镜头移动速度
37   - */
38   - boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed);
39   -
40   - /**
41   - * 云台缩放控制,使用配置文件中的默认镜头缩放速度
42   - *
43   - * @param device 控制设备
44   - * @param channelId 预览通道
45   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
46   - */
47   - boolean ptzZoomCmd(Device device,String channelId,int inOut);
48   -
49   - /**
50   - * 云台缩放控制
51   - *
52   - * @param device 控制设备
53   - * @param channelId 预览通道
54   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
55   - */
56   - boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed);
57   -
58   - /**
59   - * 云台控制,支持方向与缩放控制
60   - *
61   - * @param device 控制设备
62   - * @param channelId 预览通道
63   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
64   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
65   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
66   - * @param moveSpeed 镜头移动速度
67   - * @param zoomSpeed 镜头缩放速度
68   - */
69   - boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed);
70   -
71   - /**
72   - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
73   - *
74   - * @param device 控制设备
75   - * @param channelId 预览通道
76   - * @param cmdCode 指令码
77   - * @param parameter1 数据1
78   - * @param parameter2 数据2
79   - * @param combineCode2 组合码2
80   - */
81   - boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2);
82   -
83   - /**
84   - * 前端控制指令(用于转发上级指令)
85   - * @param device 控制设备
86   - * @param channelId 预览通道
87   - * @param cmdString 前端控制指令串
88   - */
89   - boolean fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent);
90   -
91   - /**
92   - * 请求预览视频流
93   - * @param device 视频设备
94   - * @param channelId 预览通道
95   - */
96   - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
97   -
98   - /**
99   - * 请求回放视频流
100   - *
101   - * @param device 视频设备
102   - * @param channelId 预览通道
103   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
104   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
105   - */
106   - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event errorEvent);
107   -
108   - /**
109   - * 请求历史媒体下载
110   - *
111   - * @param device 视频设备
112   - * @param channelId 预览通道
113   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
114   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
115   - * @param downloadSpeed 下载倍速参数
116   - */
117   - void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
118   - String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
119   - SipSubscribe.Event errorEvent);
120   -
121   - /**
122   - * 视频流停止
123   - */
124   - void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent);
125   - void streamByeCmd(String deviceId, String channelId, String stream, String callId);
126   -
127   - /**
128   - * 回放暂停
129   - */
130   - void playPauseCmd(Device device, StreamInfo streamInfo);
131   -
132   - /**
133   - * 回放恢复
134   - */
135   - void playResumeCmd(Device device, StreamInfo streamInfo);
136   -
137   - /**
138   - * 回放拖动播放
139   - */
140   - void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime);
141   -
142   - /**
143   - * 回放倍速播放
144   - */
145   - void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed);
146   -
147   - /**
148   - * 回放控制
149   - * @param device
150   - * @param streamInfo
151   - * @param content
152   - */
153   - void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent);
154   -
155   - /**
156   - * 语音广播
157   - *
158   - * @param device 视频设备
159   - * @param channelId 预览通道
160   - */
161   - boolean audioBroadcastCmd(Device device,String channelId);
162   -
163   - /**
164   - * 语音广播
165   - *
166   - * @param device 视频设备
167   - */
168   - void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent);
169   - boolean audioBroadcastCmd(Device device);
170   -
171   - /**
172   - * 音视频录像控制
173   - *
174   - * @param device 视频设备
175   - * @param channelId 预览通道
176   - * @param recordCmdStr 录像命令:Record / StopRecord
177   - */
178   - boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent);
179   -
180   - /**
181   - * 远程启动控制命令
182   - *
183   - * @param device 视频设备
184   - */
185   - boolean teleBootCmd(Device device);
186   -
187   - /**
188   - * 报警布防/撤防命令
189   - *
190   - * @param device 视频设备
191   - */
192   - boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent);
193   -
194   - /**
195   - * 报警复位命令
196   - *
197   - * @param device 视频设备
198   - * @param alarmMethod 报警方式(可选)
199   - * @param alarmType 报警类型(可选)
200   - */
201   - boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent);
202   -
203   - /**
204   - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
205   - *
206   - * @param device 视频设备
207   - * @param channelId 预览通道
208   - */
209   - boolean iFrameCmd(Device device, String channelId);
210   -
211   - /**
212   - * 看守位控制命令
213   - *
214   - * @param device 视频设备
215   - * @param enabled 看守位使能:1 = 开启,0 = 关闭
216   - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
217   - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
218   - */
219   - boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent);
220   -
221   - /**
222   - * 设备配置命令
223   - *
224   - * @param device 视频设备
225   - */
226   - boolean deviceConfigCmd(Device device);
227   -
228   - /**
229   - * 设备配置命令:basicParam
230   - *
231   - * @param device 视频设备
232   - * @param channelId 通道编码(可选)
233   - * @param name 设备/通道名称(可选)
234   - * @param expiration 注册过期时间(可选)
235   - * @param heartBeatInterval 心跳间隔时间(可选)
236   - * @param heartBeatCount 心跳超时次数(可选)
237   - */
238   - boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent);
239   -
240   - /**
241   - * 查询设备状态
242   - *
243   - * @param device 视频设备
244   - */
245   - boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent);
246   -
247   - /**
248   - * 查询设备信息
249   - *
250   - * @param device 视频设备
251   - * @return
252   - */
253   - boolean deviceInfoQuery(Device device);
254   -
255   - /**
256   - * 查询目录列表
257   - *
258   - * @param device 视频设备
259   - */
260   - boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent);
261   -
262   - /**
263   - * 查询录像信息
264   - *
265   - * @param device 视频设备
266   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
267   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
268   - * @param sn
269   - */
270   - boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
271   -
272   - /**
273   - * 查询报警信息
274   - *
275   - * @param device 视频设备
276   - * @param startPriority 报警起始级别(可选)
277   - * @param endPriority 报警终止级别(可选)
278   - * @param alarmMethod 报警方式条件(可选)
279   - * @param alarmType 报警类型
280   - * @param startTime 报警发生起始时间(可选)
281   - * @param endTime 报警发生终止时间(可选)
282   - * @return true = 命令发送成功
283   - */
284   - boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,
285   - String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent);
286   -
287   - /**
288   - * 查询设备配置
289   - *
290   - * @param device 视频设备
291   - * @param channelId 通道编码(可选)
292   - * @param configType 配置类型:
293   - */
294   - boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent);
295   -
296   - /**
297   - * 查询设备预置位置
298   - *
299   - * @param device 视频设备
300   - */
301   - boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent);
302   -
303   - /**
304   - * 查询移动设备位置数据
305   - *
306   - * @param device 视频设备
307   - */
308   - boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent);
309   -
310   - /**
311   - * 订阅、取消订阅移动位置
312   - *
313   - * @param device 视频设备
314   - * @return true = 命令发送成功
315   - */
316   - boolean mobilePositionSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent);
317   -
318   - /**
319   - * 订阅、取消订阅报警信息
320   - * @param device 视频设备
321   - * @param expires 订阅过期时间(0 = 取消订阅)
322   - * @param startPriority 报警起始级别(可选)
323   - * @param endPriority 报警终止级别(可选)
324   - * @param alarmType 报警类型
325   - * @param startTime 报警发生起始时间(可选)
326   - * @param endTime 报警发生终止时间(可选)
327   - * @return true = 命令发送成功
328   - */
329   - boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
330   -
331   - /**
332   - * 订阅、取消订阅目录信息
333   - * @param device 视频设备
334   - * @return true = 命令发送成功
335   - */
336   - boolean catalogSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent);
337   -
338   - /**
339   - * 拉框控制命令
340   - *
341   - * @param device 控制设备
342   - * @param channelId 通道id
343   - * @param cmdString 前端控制指令串
344   - */
345   - boolean dragZoomCmd(Device device, String channelId, String cmdString);
346   -
347   -
348   - /**
349   - * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待
350   - * @param device 设备
351   - * @param deviceAlarm 报警信息信息
352   - * @return
353   - */
354   - boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm);
355   -}
  1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd;
  2 +
  3 +import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.gb28181.bean.*;
  5 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  6 +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  8 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  9 +
  10 +import javax.sip.Dialog;
  11 +
  12 +/**
  13 + * @description:设备能力接口,用于定义设备的控制、查询能力
  14 + * @author: swwheihei
  15 + * @date: 2020年5月3日 下午9:16:34
  16 + */
  17 +public interface ISIPCommander {
  18 +
  19 + /**
  20 + * 云台方向放控制,使用配置文件中的默认镜头移动速度
  21 + *
  22 + * @param device 控制设备
  23 + * @param channelId 预览通道
  24 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  25 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  26 + */
  27 + boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown);
  28 +
  29 + /**
  30 + * 云台方向放控制
  31 + *
  32 + * @param device 控制设备
  33 + * @param channelId 预览通道
  34 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  35 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  36 + * @param moveSpeed 镜头移动速度
  37 + */
  38 + boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed);
  39 +
  40 + /**
  41 + * 云台缩放控制,使用配置文件中的默认镜头缩放速度
  42 + *
  43 + * @param device 控制设备
  44 + * @param channelId 预览通道
  45 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  46 + */
  47 + boolean ptzZoomCmd(Device device,String channelId,int inOut);
  48 +
  49 + /**
  50 + * 云台缩放控制
  51 + *
  52 + * @param device 控制设备
  53 + * @param channelId 预览通道
  54 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  55 + */
  56 + boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed);
  57 +
  58 + /**
  59 + * 云台控制,支持方向与缩放控制
  60 + *
  61 + * @param device 控制设备
  62 + * @param channelId 预览通道
  63 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  64 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  65 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  66 + * @param moveSpeed 镜头移动速度
  67 + * @param zoomSpeed 镜头缩放速度
  68 + */
  69 + boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed);
  70 +
  71 + /**
  72 + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
  73 + *
  74 + * @param device 控制设备
  75 + * @param channelId 预览通道
  76 + * @param cmdCode 指令码
  77 + * @param parameter1 数据1
  78 + * @param parameter2 数据2
  79 + * @param combineCode2 组合码2
  80 + */
  81 + boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2);
  82 +
  83 + /**
  84 + * 前端控制指令(用于转发上级指令)
  85 + * @param device 控制设备
  86 + * @param channelId 预览通道
  87 + * @param cmdString 前端控制指令串
  88 + */
  89 + boolean fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent);
  90 +
  91 + /**
  92 + * 请求预览视频流
  93 + * @param device 视频设备
  94 + * @param channelId 预览通道
  95 + */
  96 + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
  97 +
  98 + /**
  99 + * 请求回放视频流
  100 + *
  101 + * @param device 视频设备
  102 + * @param channelId 预览通道
  103 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  104 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  105 + */
  106 + void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event errorEvent);
  107 +
  108 + /**
  109 + * 请求历史媒体下载
  110 + *
  111 + * @param device 视频设备
  112 + * @param channelId 预览通道
  113 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  114 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  115 + * @param downloadSpeed 下载倍速参数
  116 + */
  117 + void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  118 + String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  119 + SipSubscribe.Event errorEvent);
  120 +
  121 + /**
  122 + * 视频流停止
  123 + */
  124 + void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent);
  125 + void streamByeCmd(String deviceId, String channelId, String stream, String callId);
  126 +
  127 + /**
  128 + * 回放暂停
  129 + */
  130 + void playPauseCmd(Device device, StreamInfo streamInfo);
  131 +
  132 + /**
  133 + * 回放恢复
  134 + */
  135 + void playResumeCmd(Device device, StreamInfo streamInfo);
  136 +
  137 + /**
  138 + * 回放拖动播放
  139 + */
  140 + void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime);
  141 +
  142 + /**
  143 + * 回放倍速播放
  144 + */
  145 + void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed);
  146 +
  147 + /**
  148 + * 回放控制
  149 + * @param device
  150 + * @param streamInfo
  151 + * @param content
  152 + */
  153 + void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent);
  154 +
  155 + /**
  156 + * 语音广播
  157 + *
  158 + * @param device 视频设备
  159 + * @param channelId 预览通道
  160 + */
  161 + boolean audioBroadcastCmd(Device device,String channelId);
  162 +
  163 + /**
  164 + * 语音广播
  165 + *
  166 + * @param device 视频设备
  167 + */
  168 + void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent);
  169 + boolean audioBroadcastCmd(Device device);
  170 +
  171 + /**
  172 + * 音视频录像控制
  173 + *
  174 + * @param device 视频设备
  175 + * @param channelId 预览通道
  176 + * @param recordCmdStr 录像命令:Record / StopRecord
  177 + */
  178 + boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent);
  179 +
  180 + /**
  181 + * 远程启动控制命令
  182 + *
  183 + * @param device 视频设备
  184 + */
  185 + boolean teleBootCmd(Device device);
  186 +
  187 + /**
  188 + * 报警布防/撤防命令
  189 + *
  190 + * @param device 视频设备
  191 + */
  192 + boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent);
  193 +
  194 + /**
  195 + * 报警复位命令
  196 + *
  197 + * @param device 视频设备
  198 + * @param alarmMethod 报警方式(可选)
  199 + * @param alarmType 报警类型(可选)
  200 + */
  201 + boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent);
  202 +
  203 + /**
  204 + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
  205 + *
  206 + * @param device 视频设备
  207 + * @param channelId 预览通道
  208 + */
  209 + boolean iFrameCmd(Device device, String channelId);
  210 +
  211 + /**
  212 + * 看守位控制命令
  213 + *
  214 + * @param device 视频设备
  215 + * @param enabled 看守位使能:1 = 开启,0 = 关闭
  216 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
  217 + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
  218 + */
  219 + boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent);
  220 +
  221 + /**
  222 + * 设备配置命令
  223 + *
  224 + * @param device 视频设备
  225 + */
  226 + boolean deviceConfigCmd(Device device);
  227 +
  228 + /**
  229 + * 设备配置命令:basicParam
  230 + *
  231 + * @param device 视频设备
  232 + * @param channelId 通道编码(可选)
  233 + * @param name 设备/通道名称(可选)
  234 + * @param expiration 注册过期时间(可选)
  235 + * @param heartBeatInterval 心跳间隔时间(可选)
  236 + * @param heartBeatCount 心跳超时次数(可选)
  237 + */
  238 + boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent);
  239 +
  240 + /**
  241 + * 查询设备状态
  242 + *
  243 + * @param device 视频设备
  244 + */
  245 + boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent);
  246 +
  247 + /**
  248 + * 查询设备信息
  249 + *
  250 + * @param device 视频设备
  251 + * @return
  252 + */
  253 + boolean deviceInfoQuery(Device device);
  254 +
  255 + /**
  256 + * 查询目录列表
  257 + *
  258 + * @param device 视频设备
  259 + */
  260 + boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent);
  261 +
  262 + /**
  263 + * 查询录像信息
  264 + *
  265 + * @param device 视频设备
  266 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  267 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  268 + * @param sn
  269 + */
  270 + boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
  271 +
  272 + /**
  273 + * 查询报警信息
  274 + *
  275 + * @param device 视频设备
  276 + * @param startPriority 报警起始级别(可选)
  277 + * @param endPriority 报警终止级别(可选)
  278 + * @param alarmMethod 报警方式条件(可选)
  279 + * @param alarmType 报警类型
  280 + * @param startTime 报警发生起始时间(可选)
  281 + * @param endTime 报警发生终止时间(可选)
  282 + * @return true = 命令发送成功
  283 + */
  284 + boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,
  285 + String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent);
  286 +
  287 + /**
  288 + * 查询设备配置
  289 + *
  290 + * @param device 视频设备
  291 + * @param channelId 通道编码(可选)
  292 + * @param configType 配置类型:
  293 + */
  294 + boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent);
  295 +
  296 + /**
  297 + * 查询设备预置位置
  298 + *
  299 + * @param device 视频设备
  300 + */
  301 + boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent);
  302 +
  303 + /**
  304 + * 查询移动设备位置数据
  305 + *
  306 + * @param device 视频设备
  307 + */
  308 + boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent);
  309 +
  310 + /**
  311 + * 订阅、取消订阅移动位置
  312 + *
  313 + * @param device 视频设备
  314 + * @return true = 命令发送成功
  315 + */
  316 + boolean mobilePositionSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent);
  317 +
  318 + /**
  319 + * 订阅、取消订阅报警信息
  320 + * @param device 视频设备
  321 + * @param expires 订阅过期时间(0 = 取消订阅)
  322 + * @param startPriority 报警起始级别(可选)
  323 + * @param endPriority 报警终止级别(可选)
  324 + * @param alarmType 报警类型
  325 + * @param startTime 报警发生起始时间(可选)
  326 + * @param endTime 报警发生终止时间(可选)
  327 + * @return true = 命令发送成功
  328 + */
  329 + boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
  330 +
  331 + /**
  332 + * 订阅、取消订阅目录信息
  333 + * @param device 视频设备
  334 + * @return true = 命令发送成功
  335 + */
  336 + boolean catalogSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent);
  337 +
  338 + /**
  339 + * 拉框控制命令
  340 + *
  341 + * @param device 控制设备
  342 + * @param channelId 通道id
  343 + * @param cmdString 前端控制指令串
  344 + */
  345 + boolean dragZoomCmd(Device device, String channelId, String cmdString);
  346 +
  347 +
  348 + /**
  349 + * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待
  350 + * @param device 设备
  351 + * @param deviceAlarm 报警信息信息
  352 + * @return
  353 + */
  354 + boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm);
  355 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
1   -package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
2   -
3   -import com.alibaba.fastjson.JSONObject;
4   -import com.genersoft.iot.vmp.common.StreamInfo;
5   -import com.genersoft.iot.vmp.conf.DynamicTask;
6   -import com.genersoft.iot.vmp.conf.SipConfig;
7   -import com.genersoft.iot.vmp.conf.UserSetting;
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.VideoStreamSessionManager;
11   -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
12   -import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
13   -import com.genersoft.iot.vmp.utils.DateUtil;
14   -import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
15   -import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
16   -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
17   -import com.genersoft.iot.vmp.service.IMediaServerService;
18   -import com.genersoft.iot.vmp.service.bean.SSRCInfo;
19   -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
20   -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
21   -import gov.nist.javax.sip.SipProviderImpl;
22   -import gov.nist.javax.sip.SipStackImpl;
23   -import gov.nist.javax.sip.message.MessageFactoryImpl;
24   -import gov.nist.javax.sip.message.SIPRequest;
25   -import gov.nist.javax.sip.stack.SIPDialog;
26   -import org.slf4j.Logger;
27   -import org.slf4j.LoggerFactory;
28   -import org.springframework.beans.factory.annotation.Autowired;
29   -import org.springframework.beans.factory.annotation.Qualifier;
30   -import org.springframework.context.annotation.DependsOn;
31   -import org.springframework.stereotype.Component;
32   -import org.springframework.util.StringUtils;
33   -
34   -import javax.sip.*;
35   -import javax.sip.address.Address;
36   -import javax.sip.address.SipURI;
37   -import javax.sip.address.URI;
38   -import javax.sip.header.*;
39   -import javax.sip.message.Request;
40   -import java.lang.reflect.Field;
41   -import java.text.ParseException;
42   -import java.util.ArrayList;
43   -import java.util.HashSet;
44   -import java.util.List;
45   -
46   -/**
47   - * @description:设备能力接口,用于定义设备的控制、查询能力
48   - * @author: swwheihei
49   - * @date: 2020年5月3日 下午9:22:48
50   - */
51   -@Component
52   -@DependsOn("sipLayer")
53   -public class SIPCommander implements ISIPCommander {
54   -
55   - private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
56   -
57   - @Autowired
58   - private SipConfig sipConfig;
59   -
60   - @Autowired
61   - private SipFactory sipFactory;
62   -
63   - @Autowired
64   - @Qualifier(value="tcpSipProvider")
65   - private SipProviderImpl tcpSipProvider;
66   -
67   - @Autowired
68   - @Qualifier(value="udpSipProvider")
69   - private SipProviderImpl udpSipProvider;
70   -
71   - @Autowired
72   - private SIPRequestHeaderProvider headerProvider;
73   -
74   - @Autowired
75   - private VideoStreamSessionManager streamSession;
76   -
77   - @Autowired
78   - private IVideoManagerStorage storager;
79   -
80   - @Autowired
81   - private IRedisCatchStorage redisCatchStorage;
82   -
83   - @Autowired
84   - private UserSetting userSetting;
85   -
86   - @Autowired
87   - private ZLMHttpHookSubscribe subscribe;
88   -
89   - @Autowired
90   - private SipSubscribe sipSubscribe;
91   -
92   - @Autowired
93   - private IMediaServerService mediaServerService;
94   -
95   - @Autowired
96   - private DynamicTask dynamicTask;
97   -
98   -
99   - /**
100   - * 云台方向放控制,使用配置文件中的默认镜头移动速度
101   - *
102   - * @param device 控制设备
103   - * @param channelId 预览通道
104   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
105   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
106   - */
107   - @Override
108   - public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) {
109   - return ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0);
110   - }
111   -
112   - /**
113   - * 云台方向放控制
114   - *
115   - * @param device 控制设备
116   - * @param channelId 预览通道
117   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
118   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
119   - * @param moveSpeed 镜头移动速度
120   - */
121   - @Override
122   - public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) {
123   - return ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0);
124   - }
125   -
126   - /**
127   - * 云台缩放控制,使用配置文件中的默认镜头缩放速度
128   - *
129   - * @param device 控制设备
130   - * @param channelId 预览通道
131   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
132   - */
133   - @Override
134   - public boolean ptzZoomCmd(Device device, String channelId, int inOut) {
135   - return ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed());
136   - }
137   -
138   - /**
139   - * 云台缩放控制
140   - *
141   - * @param device 控制设备
142   - * @param channelId 预览通道
143   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
144   - * @param zoomSpeed 镜头缩放速度
145   - */
146   - @Override
147   - public boolean ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) {
148   - return ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed);
149   - }
150   -
151   - /**
152   - * 云台指令码计算
153   - *
154   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
155   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
156   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
157   - * @param moveSpeed 镜头移动速度 默认 0XFF (0-255)
158   - * @param zoomSpeed 镜头缩放速度 默认 0X1 (0-255)
159   - */
160   - public static String cmdString(int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) {
161   - int cmdCode = 0;
162   - if (leftRight == 2) {
163   - cmdCode|=0x01; // 右移
164   - } else if(leftRight == 1) {
165   - cmdCode|=0x02; // 左移
166   - }
167   - if (upDown == 2) {
168   - cmdCode|=0x04; // 下移
169   - } else if(upDown == 1) {
170   - cmdCode|=0x08; // 上移
171   - }
172   - if (inOut == 2) {
173   - cmdCode |= 0x10; // 放大
174   - } else if(inOut == 1) {
175   - cmdCode |= 0x20; // 缩小
176   - }
177   - StringBuilder builder = new StringBuilder("A50F01");
178   - String strTmp;
179   - strTmp = String.format("%02X", cmdCode);
180   - builder.append(strTmp, 0, 2);
181   - strTmp = String.format("%02X", moveSpeed);
182   - builder.append(strTmp, 0, 2);
183   - builder.append(strTmp, 0, 2);
184   - strTmp = String.format("%X", zoomSpeed);
185   - builder.append(strTmp, 0, 1).append("0");
186   - //计算校验码
187   - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + moveSpeed + moveSpeed + (zoomSpeed /*<< 4*/ & 0XF0)) % 0X100;
188   - strTmp = String.format("%02X", checkCode);
189   - builder.append(strTmp, 0, 2);
190   - return builder.toString();
191   -}
192   -
193   - /**
194   - * 云台指令码计算
195   - *
196   - * @param cmdCode 指令码
197   - * @param parameter1 数据1
198   - * @param parameter2 数据2
199   - * @param combineCode2 组合码2
200   - */
201   - public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {
202   - StringBuilder builder = new StringBuilder("A50F01");
203   - String strTmp;
204   - strTmp = String.format("%02X", cmdCode);
205   - builder.append(strTmp, 0, 2);
206   - strTmp = String.format("%02X", parameter1);
207   - builder.append(strTmp, 0, 2);
208   - strTmp = String.format("%02X", parameter2);
209   - builder.append(strTmp, 0, 2);
210   - strTmp = String.format("%X", combineCode2);
211   - builder.append(strTmp, 0, 1).append("0");
212   - //计算校验码
213   - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;
214   - strTmp = String.format("%02X", checkCode);
215   - builder.append(strTmp, 0, 2);
216   - return builder.toString();
217   - }
218   -
219   - /**
220   - * 云台控制,支持方向与缩放控制
221   - *
222   - * @param device 控制设备
223   - * @param channelId 预览通道
224   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
225   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
226   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
227   - * @param moveSpeed 镜头移动速度
228   - * @param zoomSpeed 镜头缩放速度
229   - */
230   - @Override
231   - public boolean ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,
232   - int zoomSpeed) {
233   - try {
234   - String cmdStr= cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed);
235   - StringBuffer ptzXml = new StringBuffer(200);
236   - String charset = device.getCharset();
237   - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
238   - ptzXml.append("<Control>\r\n");
239   - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
240   - ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
241   - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
242   - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
243   - ptzXml.append("<Info>\r\n");
244   - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
245   - ptzXml.append("</Info>\r\n");
246   - ptzXml.append("</Control>\r\n");
247   -
248   - String tm = Long.toString(System.currentTimeMillis());
249   -
250   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
251   - : udpSipProvider.getNewCallId();
252   -
253   - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
254   -
255   - transmitRequest(device, request);
256   - return true;
257   - } catch (SipException | ParseException | InvalidArgumentException e) {
258   - e.printStackTrace();
259   - }
260   - return false;
261   - }
262   -
263   - /**
264   - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
265   - *
266   - * @param device 控制设备
267   - * @param channelId 预览通道
268   - * @param cmdCode 指令码
269   - * @param parameter1 数据1
270   - * @param parameter2 数据2
271   - * @param combineCode2 组合码2
272   - */
273   - @Override
274   - public boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) {
275   - try {
276   - String cmdStr= frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);
277   - logger.debug("控制字符串:" + cmdStr);
278   - StringBuffer ptzXml = new StringBuffer(200);
279   - String charset = device.getCharset();
280   - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
281   - ptzXml.append("<Control>\r\n");
282   - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
283   - ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
284   - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
285   - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
286   - ptzXml.append("<Info>\r\n");
287   - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
288   - ptzXml.append("</Info>\r\n");
289   - ptzXml.append("</Control>\r\n");
290   -
291   - String tm = Long.toString(System.currentTimeMillis());
292   -
293   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
294   - : udpSipProvider.getNewCallId();
295   -
296   - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
297   - transmitRequest(device, request);
298   - return true;
299   - } catch (SipException | ParseException | InvalidArgumentException e) {
300   - e.printStackTrace();
301   - }
302   - return false;
303   - }
304   -
305   - /**
306   - * 前端控制指令(用于转发上级指令)
307   - * @param device 控制设备
308   - * @param channelId 预览通道
309   - * @param cmdString 前端控制指令串
310   - */
311   - @Override
312   - public boolean fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) {
313   - try {
314   - StringBuffer ptzXml = new StringBuffer(200);
315   - String charset = device.getCharset();
316   - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
317   - ptzXml.append("<Control>\r\n");
318   - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
319   - ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
320   - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
321   - ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n");
322   - ptzXml.append("<Info>\r\n");
323   - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
324   - ptzXml.append("</Info>\r\n");
325   - ptzXml.append("</Control>\r\n");
326   -
327   - String tm = Long.toString(System.currentTimeMillis());
328   -
329   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
330   - : udpSipProvider.getNewCallId();
331   -
332   - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
333   - transmitRequest(device, request, errorEvent, okEvent);
334   - return true;
335   - } catch (SipException | ParseException | InvalidArgumentException e) {
336   - e.printStackTrace();
337   - }
338   - return false;
339   - }
340   -
341   - /**
342   - * 请求预览视频流
343   - * @param device 视频设备
344   - * @param channelId 预览通道
345   - * @param event hook订阅
346   - * @param errorEvent sip错误订阅
347   - */
348   - @Override
349   - public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
350   - ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
351   - String streamId = ssrcInfo.getStream();
352   - try {
353   - if (device == null) {
354   - return;
355   - }
356   - String streamMode = device.getStreamMode().toUpperCase();
357   -
358   - logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
359   - // 添加订阅
360   - JSONObject subscribeKey = new JSONObject();
361   - subscribeKey.put("app", "rtp");
362   - subscribeKey.put("stream", streamId);
363   - subscribeKey.put("regist", true);
364   - subscribeKey.put("schema", "rtmp");
365   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
366   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
367   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
368   - if (event != null) {
369   - event.response(mediaServerItemInUse, json);
370   - }
371   - });
372   - //
373   - StringBuffer content = new StringBuffer(200);
374   - content.append("v=0\r\n");
375   - content.append("o="+ channelId+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
376   - content.append("s=Play\r\n");
377   - content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
378   - content.append("t=0 0\r\n");
379   -
380   - if (userSetting.isSeniorSdp()) {
381   - if("TCP-PASSIVE".equals(streamMode)) {
382   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
383   - }else if ("TCP-ACTIVE".equals(streamMode)) {
384   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
385   - }else if("UDP".equals(streamMode)) {
386   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
387   - }
388   - content.append("a=recvonly\r\n");
389   - content.append("a=rtpmap:96 PS/90000\r\n");
390   - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
391   - content.append("a=rtpmap:126 H264/90000\r\n");
392   - content.append("a=rtpmap:125 H264S/90000\r\n");
393   - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
394   - content.append("a=rtpmap:99 H265/90000\r\n");
395   - content.append("a=rtpmap:98 H264/90000\r\n");
396   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
397   - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
398   - content.append("a=setup:passive\r\n");
399   - content.append("a=connection:new\r\n");
400   - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
401   - content.append("a=setup:active\r\n");
402   - content.append("a=connection:new\r\n");
403   - }
404   - }else {
405   - if("TCP-PASSIVE".equals(streamMode)) {
406   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
407   - }else if ("TCP-ACTIVE".equals(streamMode)) {
408   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
409   - }else if("UDP".equals(streamMode)) {
410   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
411   - }
412   - content.append("a=recvonly\r\n");
413   - content.append("a=rtpmap:96 PS/90000\r\n");
414   - content.append("a=rtpmap:98 H264/90000\r\n");
415   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
416   - content.append("a=rtpmap:99 H265/90000\r\n");
417   - if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
418   - content.append("a=setup:passive\r\n");
419   - content.append("a=connection:new\r\n");
420   - } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
421   - content.append("a=setup:active\r\n");
422   - content.append("a=connection:new\r\n");
423   - }
424   - }
425   -
426   - content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc
427   - // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
428   -// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备
429   -
430   - String tm = Long.toString(System.currentTimeMillis());
431   -
432   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
433   - : udpSipProvider.getNewCallId();
434   -
435   - Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrcInfo.getSsrc(), callIdHeader);
436   -
437   - transmitRequest(device, request, (e -> {
438   - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
439   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
440   - errorEvent.response(e);
441   - }), e ->{
442   - // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
443   - streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play);
444   - streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog);
445   - okEvent.response(e);
446   - });
447   -
448   -
449   - } catch ( SipException | ParseException | InvalidArgumentException e) {
450   - e.printStackTrace();
451   - }
452   - }
453   -
454   - /**
455   - * 请求回放视频流
456   - *
457   - * @param device 视频设备
458   - * @param channelId 预览通道
459   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
460   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
461   - */
462   - @Override
463   - public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
464   - String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
465   - SipSubscribe.Event errorEvent) {
466   - try {
467   -
468   - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
469   -
470   - StringBuffer content = new StringBuffer(200);
471   - content.append("v=0\r\n");
472   - content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
473   - content.append("s=Playback\r\n");
474   - content.append("u="+channelId+":0\r\n");
475   - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
476   - content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
477   - +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
478   -
479   - String streamMode = device.getStreamMode().toUpperCase();
480   -
481   - if (userSetting.isSeniorSdp()) {
482   - if("TCP-PASSIVE".equals(streamMode)) {
483   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
484   - }else if ("TCP-ACTIVE".equals(streamMode)) {
485   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
486   - }else if("UDP".equals(streamMode)) {
487   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
488   - }
489   - content.append("a=recvonly\r\n");
490   - content.append("a=rtpmap:96 PS/90000\r\n");
491   - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
492   - content.append("a=rtpmap:126 H264/90000\r\n");
493   - content.append("a=rtpmap:125 H264S/90000\r\n");
494   - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
495   - content.append("a=rtpmap:99 H265/90000\r\n");
496   - content.append("a=rtpmap:98 H264/90000\r\n");
497   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
498   - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
499   - content.append("a=setup:passive\r\n");
500   - content.append("a=connection:new\r\n");
501   - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
502   - content.append("a=setup:active\r\n");
503   - content.append("a=connection:new\r\n");
504   - }
505   - }else {
506   - if("TCP-PASSIVE".equals(streamMode)) {
507   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
508   - }else if ("TCP-ACTIVE".equals(streamMode)) {
509   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
510   - }else if("UDP".equals(streamMode)) {
511   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
512   - }
513   - content.append("a=recvonly\r\n");
514   - content.append("a=rtpmap:96 PS/90000\r\n");
515   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
516   - content.append("a=rtpmap:98 H264/90000\r\n");
517   - content.append("a=rtpmap:99 H265/90000\r\n");
518   - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
519   - content.append("a=setup:passive\r\n");
520   - content.append("a=connection:new\r\n");
521   - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
522   - content.append("a=setup:active\r\n");
523   - content.append("a=connection:new\r\n");
524   - }
525   - }
526   -
527   - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
528   -
529   - String tm = Long.toString(System.currentTimeMillis());
530   -
531   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
532   - : udpSipProvider.getNewCallId();
533   -
534   - // 添加订阅
535   - JSONObject subscribeKey = new JSONObject();
536   - subscribeKey.put("app", "rtp");
537   - subscribeKey.put("stream", ssrcInfo.getStream());
538   - subscribeKey.put("regist", true);
539   - subscribeKey.put("schema", "rtmp");
540   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
541   - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey);
542   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
543   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
544   - if (hookEvent != null) {
545   - InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream());
546   - hookEvent.call(inviteStreamInfo);
547   - }
548   - });
549   - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
550   -
551   - transmitRequest(device, request, errorEvent, okEvent -> {
552   - ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
553   - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.playback);
554   - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
555   - });
556   - if (inviteStreamCallback != null) {
557   - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
558   - }
559   - } catch ( SipException | ParseException | InvalidArgumentException e) {
560   - e.printStackTrace();
561   - }
562   - }
563   -
564   - /**
565   - * 请求历史媒体下载
566   - *
567   - * @param device 视频设备
568   - * @param channelId 预览通道
569   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
570   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
571   - * @param downloadSpeed 下载倍速参数
572   - */
573   - @Override
574   - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
575   - String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
576   - SipSubscribe.Event errorEvent) {
577   - try {
578   - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
579   -
580   - StringBuffer content = new StringBuffer(200);
581   - content.append("v=0\r\n");
582   - content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
583   - content.append("s=Download\r\n");
584   - content.append("u="+channelId+":0\r\n");
585   - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
586   - content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
587   - +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
588   -
589   - String streamMode = device.getStreamMode().toUpperCase();
590   -
591   - if (userSetting.isSeniorSdp()) {
592   - if("TCP-PASSIVE".equals(streamMode)) {
593   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
594   - }else if ("TCP-ACTIVE".equals(streamMode)) {
595   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
596   - }else if("UDP".equals(streamMode)) {
597   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
598   - }
599   - content.append("a=recvonly\r\n");
600   - content.append("a=rtpmap:96 PS/90000\r\n");
601   - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
602   - content.append("a=rtpmap:126 H264/90000\r\n");
603   - content.append("a=rtpmap:125 H264S/90000\r\n");
604   - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
605   - content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
606   - content.append("a=fmtp:99 profile-level-id=3\r\n");
607   - content.append("a=rtpmap:98 H264/90000\r\n");
608   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
609   - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
610   - content.append("a=setup:passive\r\n");
611   - content.append("a=connection:new\r\n");
612   - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
613   - content.append("a=setup:active\r\n");
614   - content.append("a=connection:new\r\n");
615   - }
616   - }else {
617   - if("TCP-PASSIVE".equals(streamMode)) {
618   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
619   - }else if ("TCP-ACTIVE".equals(streamMode)) {
620   - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
621   - }else if("UDP".equals(streamMode)) {
622   - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
623   - }
624   - content.append("a=recvonly\r\n");
625   - content.append("a=rtpmap:96 PS/90000\r\n");
626   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
627   - content.append("a=rtpmap:98 H264/90000\r\n");
628   - content.append("a=rtpmap:99 H265/90000\r\n");
629   - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
630   - content.append("a=setup:passive\r\n");
631   - content.append("a=connection:new\r\n");
632   - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
633   - content.append("a=setup:active\r\n");
634   - content.append("a=connection:new\r\n");
635   - }
636   - }
637   - content.append("a=downloadspeed:" + downloadSpeed + "\r\n");
638   -
639   - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
640   -
641   - String tm = Long.toString(System.currentTimeMillis());
642   -
643   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
644   - : udpSipProvider.getNewCallId();
645   -
646   - // 添加订阅
647   - JSONObject subscribeKey = new JSONObject();
648   - subscribeKey.put("app", "rtp");
649   - subscribeKey.put("stream", ssrcInfo.getStream());
650   - subscribeKey.put("regist", true);
651   - subscribeKey.put("mediaServerId", mediaServerItem.getId());
652   - logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
653   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
654   - (MediaServerItem mediaServerItemInUse, JSONObject json)->{
655   - hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
656   - subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
657   - subscribeKey.put("regist", false);
658   - subscribeKey.put("schema", "rtmp");
659   - // 添加流注销的订阅,注销了后向设备发送bye
660   - subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
661   - (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd)->{
662   - ClientTransaction transaction = streamSession.getTransaction(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
663   - if (transaction != null) {
664   - logger.info("[录像]下载结束, 发送BYE");
665   - streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
666   - }
667   - });
668   - });
669   -
670   - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
671   - if (inviteStreamCallback != null) {
672   - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
673   - }
674   - transmitRequest(device, request, errorEvent, okEvent->{
675   - ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
676   - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.download);
677   - streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
678   - });
679   -
680   -
681   - } catch ( SipException | ParseException | InvalidArgumentException e) {
682   - e.printStackTrace();
683   - }
684   - }
685   -
686   - /**
687   - * 视频流停止, 不使用回调
688   - */
689   - @Override
690   - public void streamByeCmd(String deviceId, String channelId, String stream, String callId) {
691   - streamByeCmd(deviceId, channelId, stream, callId, null);
692   - }
693   -
694   - /**
695   - * 视频流停止
696   - */
697   - @Override
698   - public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) {
699   - try {
700   - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, callId, stream);
701   - ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId, stream, callId);
702   -
703   - if (transaction == null ) {
704   - logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
705   - SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
706   - if (okEvent != null) {
707   - okEvent.response(eventResult);
708   - }
709   - return;
710   - }
711   - SIPDialog dialog;
712   - if (callId != null) {
713   - dialog = streamSession.getDialogByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), callId);
714   - }else {
715   - if (stream == null && ssrcTransaction == null && ssrcTransaction.getStream() == null) {
716   - return;
717   - }
718   - dialog = streamSession.getDialogByStream(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
719   - }
720   - mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());
721   - mediaServerService.closeRTPServer(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
722   - streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
723   -
724   - if (dialog == null) {
725   - logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId());
726   - return;
727   - }
728   - SipStack sipStack = udpSipProvider.getSipStack();
729   - SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog);
730   - if (dialog != sipDialog) {
731   - dialog = sipDialog;
732   - }else {
733   - dialog.setSipProvider(udpSipProvider);
734   - try {
735   - Field sipStackField = SIPDialog.class.getDeclaredField("sipStack");
736   - sipStackField.setAccessible(true);
737   - sipStackField.set(dialog, sipStack);
738   - Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners");
739   - eventListenersField.setAccessible(true);
740   - eventListenersField.set(dialog, new HashSet<>());
741   - } catch (NoSuchFieldException | IllegalAccessException e) {
742   - e.printStackTrace();
743   - }
744   - }
745   -
746   - Request byeRequest = dialog.createRequest(Request.BYE);
747   - SipURI byeURI = (SipURI) byeRequest.getRequestURI();
748   - SIPRequest request = (SIPRequest)transaction.getRequest();
749   - byeURI.setHost(request.getRemoteAddress().getHostAddress());
750   - byeURI.setPort(request.getRemotePort());
751   - ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME);
752   - String protocol = viaHeader.getTransport().toUpperCase();
753   - ClientTransaction clientTransaction = null;
754   - if("TCP".equals(protocol)) {
755   - clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest);
756   - } else if("UDP".equals(protocol)) {
757   - clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
758   - }
759   -
760   - CallIdHeader callIdHeader = (CallIdHeader) byeRequest.getHeader(CallIdHeader.NAME);
761   - if (okEvent != null) {
762   - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);
763   - }
764   -
765   - dialog.sendRequest(clientTransaction);
766   -
767   - } catch (SipException | ParseException e) {
768   - e.printStackTrace();
769   - }
770   - }
771   -
772   - /**
773   - * 语音广播
774   - *
775   - * @param device 视频设备
776   - * @param channelId 预览通道
777   - */
778   - @Override
779   - public boolean audioBroadcastCmd(Device device, String channelId) {
780   - // 改为新的实现
781   - return false;
782   - }
783   -
784   - /**
785   - * 语音广播
786   - *
787   - * @param device 视频设备
788   - */
789   - @Override
790   - public boolean audioBroadcastCmd(Device device) {
791   - try {
792   - StringBuffer broadcastXml = new StringBuffer(200);
793   - String charset = device.getCharset();
794   - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
795   - broadcastXml.append("<Notify>\r\n");
796   - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
797   - broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
798   - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
799   - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
800   - broadcastXml.append("</Notify>\r\n");
801   -
802   - String tm = Long.toString(System.currentTimeMillis());
803   -
804   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
805   - : udpSipProvider.getNewCallId();
806   -
807   - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), "z9hG4bK-ViaBcst-" + tm, "FromBcst" + tm, null, callIdHeader);
808   - transmitRequest(device, request);
809   - return true;
810   - } catch (SipException | ParseException | InvalidArgumentException e) {
811   - e.printStackTrace();
812   - }
813   - return false;
814   - }
815   - @Override
816   - public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) {
817   - try {
818   - StringBuffer broadcastXml = new StringBuffer(200);
819   - String charset = device.getCharset();
820   - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
821   - broadcastXml.append("<Notify>\r\n");
822   - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
823   - broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
824   - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
825   - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
826   - broadcastXml.append("</Notify>\r\n");
827   -
828   - String tm = Long.toString(System.currentTimeMillis());
829   -
830   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
831   - : udpSipProvider.getNewCallId();
832   -
833   - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), "z9hG4bK-ViaBcst-" + tm, "FromBcst" + tm, null, callIdHeader);
834   - transmitRequest(device, request, errorEvent);
835   - } catch (SipException | ParseException | InvalidArgumentException e) {
836   - e.printStackTrace();
837   - }
838   - }
839   -
840   -
841   - /**
842   - * 音视频录像控制
843   - *
844   - * @param device 视频设备
845   - * @param channelId 预览通道
846   - * @param recordCmdStr 录像命令:Record / StopRecord
847   - */
848   - @Override
849   - public boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) {
850   - try {
851   - StringBuffer cmdXml = new StringBuffer(200);
852   - String charset = device.getCharset();
853   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
854   - cmdXml.append("<Control>\r\n");
855   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
856   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
857   - if (StringUtils.isEmpty(channelId)) {
858   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
859   - } else {
860   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
861   - }
862   - cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n");
863   - cmdXml.append("</Control>\r\n");
864   -
865   - String tm = Long.toString(System.currentTimeMillis());
866   -
867   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
868   - : udpSipProvider.getNewCallId();
869   -
870   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromRecord" + tm, null, callIdHeader);
871   - transmitRequest(device, request, errorEvent);
872   - return true;
873   - } catch (SipException | ParseException | InvalidArgumentException e) {
874   - e.printStackTrace();
875   - return false;
876   - }
877   - }
878   -
879   - /**
880   - * 远程启动控制命令
881   - *
882   - * @param device 视频设备
883   - */
884   - @Override
885   - public boolean teleBootCmd(Device device) {
886   - try {
887   - StringBuffer cmdXml = new StringBuffer(200);
888   - String charset = device.getCharset();
889   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
890   - cmdXml.append("<Control>\r\n");
891   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
892   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
893   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
894   - cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n");
895   - cmdXml.append("</Control>\r\n");
896   -
897   - String tm = Long.toString(System.currentTimeMillis());
898   -
899   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
900   - : udpSipProvider.getNewCallId();
901   -
902   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromBoot" + tm, null, callIdHeader);
903   - transmitRequest(device, request);
904   - return true;
905   - } catch (SipException | ParseException | InvalidArgumentException e) {
906   - e.printStackTrace();
907   - return false;
908   - }
909   - }
910   -
911   - /**
912   - * 报警布防/撤防命令
913   - *
914   - * @param device 视频设备
915   - * @param guardCmdStr "SetGuard"/"ResetGuard"
916   - */
917   - @Override
918   - public boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) {
919   - try {
920   - StringBuffer cmdXml = new StringBuffer(200);
921   - String charset = device.getCharset();
922   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
923   - cmdXml.append("<Control>\r\n");
924   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
925   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
926   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
927   - cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");
928   - cmdXml.append("</Control>\r\n");
929   -
930   - String tm = Long.toString(System.currentTimeMillis());
931   -
932   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
933   - : udpSipProvider.getNewCallId();
934   -
935   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromGuard" + tm, null, callIdHeader);
936   - transmitRequest(device, request, errorEvent);
937   - return true;
938   - } catch (SipException | ParseException | InvalidArgumentException e) {
939   - e.printStackTrace();
940   - return false;
941   - }
942   - }
943   -
944   - /**
945   - * 报警复位命令
946   - *
947   - * @param device 视频设备
948   - */
949   - @Override
950   - public boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) {
951   - try {
952   - StringBuffer cmdXml = new StringBuffer(200);
953   - String charset = device.getCharset();
954   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
955   - cmdXml.append("<Control>\r\n");
956   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
957   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
958   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
959   - cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
960   - if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
961   - cmdXml.append("<Info>\r\n");
962   - }
963   - if (!StringUtils.isEmpty(alarmMethod)) {
964   - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
965   - }
966   - if (!StringUtils.isEmpty(alarmType)) {
967   - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
968   - }
969   - if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
970   - cmdXml.append("</Info>\r\n");
971   - }
972   - cmdXml.append("</Control>\r\n");
973   -
974   - String tm = Long.toString(System.currentTimeMillis());
975   -
976   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
977   - : udpSipProvider.getNewCallId();
978   -
979   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromAlarm" + tm, null, callIdHeader);
980   - transmitRequest(device, request, errorEvent);
981   - return true;
982   - } catch (SipException | ParseException | InvalidArgumentException e) {
983   - e.printStackTrace();
984   - return false;
985   - }
986   - }
987   -
988   - /**
989   - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
990   - *
991   - * @param device 视频设备
992   - * @param channelId 预览通道
993   - */
994   - @Override
995   - public boolean iFrameCmd(Device device, String channelId) {
996   - try {
997   - StringBuffer cmdXml = new StringBuffer(200);
998   - String charset = device.getCharset();
999   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1000   - cmdXml.append("<Control>\r\n");
1001   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
1002   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1003   - if (StringUtils.isEmpty(channelId)) {
1004   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1005   - } else {
1006   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1007   - }
1008   - cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n");
1009   - cmdXml.append("</Control>\r\n");
1010   -
1011   - String tm = Long.toString(System.currentTimeMillis());
1012   -
1013   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1014   - : udpSipProvider.getNewCallId();
1015   -
1016   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromBoot" + tm, null, callIdHeader);
1017   - transmitRequest(device, request);
1018   - return true;
1019   - } catch (SipException | ParseException | InvalidArgumentException e) {
1020   - e.printStackTrace();
1021   - return false;
1022   - }
1023   - }
1024   -
1025   - /**
1026   - * 看守位控制命令
1027   - *
1028   - * @param device 视频设备
1029   - * @param enabled 看守位使能:1 = 开启,0 = 关闭
1030   - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
1031   - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
1032   - */
1033   - @Override
1034   - public boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) {
1035   - try {
1036   - StringBuffer cmdXml = new StringBuffer(200);
1037   - String charset = device.getCharset();
1038   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1039   - cmdXml.append("<Control>\r\n");
1040   - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
1041   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1042   - if (StringUtils.isEmpty(channelId)) {
1043   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1044   - } else {
1045   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1046   - }
1047   - cmdXml.append("<HomePosition>\r\n");
1048   - if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
1049   - cmdXml.append("<Enabled>1</Enabled>\r\n");
1050   - if (NumericUtil.isInteger(resetTime)) {
1051   - cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
1052   - } else {
1053   - cmdXml.append("<ResetTime>0</ResetTime>\r\n");
1054   - }
1055   - if (NumericUtil.isInteger(presetIndex)) {
1056   - cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
1057   - } else {
1058   - cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
1059   - }
1060   - } else {
1061   - cmdXml.append("<Enabled>0</Enabled>\r\n");
1062   - }
1063   - cmdXml.append("</HomePosition>\r\n");
1064   - cmdXml.append("</Control>\r\n");
1065   -
1066   - String tm = Long.toString(System.currentTimeMillis());
1067   -
1068   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1069   - : udpSipProvider.getNewCallId();
1070   -
1071   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromGuard" + tm, null, callIdHeader);
1072   - transmitRequest(device, request, errorEvent);
1073   - return true;
1074   - } catch (SipException | ParseException | InvalidArgumentException e) {
1075   - e.printStackTrace();
1076   - return false;
1077   - }
1078   - }
1079   -
1080   - /**
1081   - * 设备配置命令
1082   - *
1083   - * @param device 视频设备
1084   - */
1085   - @Override
1086   - public boolean deviceConfigCmd(Device device) {
1087   - // TODO Auto-generated method stub
1088   - return false;
1089   - }
1090   -
1091   - /**
1092   - * 设备配置命令:basicParam
1093   - *
1094   - * @param device 视频设备
1095   - * @param channelId 通道编码(可选)
1096   - * @param name 设备/通道名称(可选)
1097   - * @param expiration 注册过期时间(可选)
1098   - * @param heartBeatInterval 心跳间隔时间(可选)
1099   - * @param heartBeatCount 心跳超时次数(可选)
1100   - */
1101   - @Override
1102   - public boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration,
1103   - String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) {
1104   - try {
1105   - StringBuffer cmdXml = new StringBuffer(200);
1106   - String charset = device.getCharset();
1107   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1108   - cmdXml.append("<Control>\r\n");
1109   - cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
1110   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1111   - if (StringUtils.isEmpty(channelId)) {
1112   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1113   - } else {
1114   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1115   - }
1116   - cmdXml.append("<BasicParam>\r\n");
1117   - if (!StringUtils.isEmpty(name)) {
1118   - cmdXml.append("<Name>" + name + "</Name>\r\n");
1119   - }
1120   - if (NumericUtil.isInteger(expiration)) {
1121   - if (Integer.valueOf(expiration) > 0) {
1122   - cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n");
1123   - }
1124   - }
1125   - if (NumericUtil.isInteger(heartBeatInterval)) {
1126   - if (Integer.valueOf(heartBeatInterval) > 0) {
1127   - cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n");
1128   - }
1129   - }
1130   - if (NumericUtil.isInteger(heartBeatCount)) {
1131   - if (Integer.valueOf(heartBeatCount) > 0) {
1132   - cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n");
1133   - }
1134   - }
1135   - cmdXml.append("</BasicParam>\r\n");
1136   - cmdXml.append("</Control>\r\n");
1137   -
1138   - String tm = Long.toString(System.currentTimeMillis());
1139   -
1140   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1141   - : udpSipProvider.getNewCallId();
1142   -
1143   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromConfig" + tm, null, callIdHeader);
1144   - transmitRequest(device, request, errorEvent);
1145   - return true;
1146   - } catch (SipException | ParseException | InvalidArgumentException e) {
1147   - e.printStackTrace();
1148   - return false;
1149   - }
1150   - }
1151   -
1152   - /**
1153   - * 查询设备状态
1154   - *
1155   - * @param device 视频设备
1156   - */
1157   - @Override
1158   - public boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) {
1159   - try {
1160   - String charset = device.getCharset();
1161   - StringBuffer catalogXml = new StringBuffer(200);
1162   - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1163   - catalogXml.append("<Query>\r\n");
1164   - catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
1165   - catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1166   - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1167   - catalogXml.append("</Query>\r\n");
1168   -
1169   - String tm = Long.toString(System.currentTimeMillis());
1170   -
1171   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1172   - : udpSipProvider.getNewCallId();
1173   -
1174   - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, "FromStatus" + tm, null, callIdHeader);
1175   -
1176   - transmitRequest(device, request, errorEvent);
1177   - return true;
1178   -
1179   - } catch (SipException | ParseException | InvalidArgumentException e) {
1180   - e.printStackTrace();
1181   - return false;
1182   - }
1183   - }
1184   -
1185   - /**
1186   - * 查询设备信息
1187   - *
1188   - * @param device 视频设备
1189   - */
1190   - @Override
1191   - public boolean deviceInfoQuery(Device device) {
1192   - try {
1193   - StringBuffer catalogXml = new StringBuffer(200);
1194   - String charset = device.getCharset();
1195   - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1196   - catalogXml.append("<Query>\r\n");
1197   - catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
1198   - catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1199   - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1200   - catalogXml.append("</Query>\r\n");
1201   -
1202   - String tm = Long.toString(System.currentTimeMillis());
1203   -
1204   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1205   - : udpSipProvider.getNewCallId();
1206   -
1207   - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "z9hG4bK-ViaDeviceInfo-" + tm, "FromDev" + tm, null, callIdHeader);
1208   -
1209   - transmitRequest(device, request);
1210   -
1211   - } catch (SipException | ParseException | InvalidArgumentException e) {
1212   - e.printStackTrace();
1213   - return false;
1214   - }
1215   - return true;
1216   - }
1217   -
1218   - /**
1219   - * 查询目录列表
1220   - *
1221   - * @param device 视频设备
1222   - */
1223   - @Override
1224   - public boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) {
1225   - try {
1226   - StringBuffer catalogXml = new StringBuffer(200);
1227   - String charset = device.getCharset();
1228   - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1229   - catalogXml.append("<Query>\r\n");
1230   - catalogXml.append("<CmdType>Catalog</CmdType>\r\n");
1231   - catalogXml.append("<SN>" + sn + "</SN>\r\n");
1232   - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1233   - catalogXml.append("</Query>\r\n");
1234   -
1235   - String tm = Long.toString(System.currentTimeMillis());
1236   -
1237   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1238   - : udpSipProvider.getNewCallId();
1239   -
1240   - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "z9hG4bK-ViaCatalog-" + tm, "FromCat" + tm, null, callIdHeader);
1241   -
1242   - transmitRequest(device, request, errorEvent);
1243   - } catch (SipException | ParseException | InvalidArgumentException e) {
1244   - e.printStackTrace();
1245   - return false;
1246   - }
1247   - return true;
1248   - }
1249   -
1250   - /**
1251   - * 查询录像信息
1252   - *
1253   - * @param device 视频设备
1254   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
1255   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
1256   - */
1257   - @Override
1258   - public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
1259   - if (secrecy == null) {
1260   - secrecy = 0;
1261   - }
1262   - if (type == null) {
1263   - type = "all";
1264   - }
1265   - try {
1266   - StringBuffer recordInfoXml = new StringBuffer(200);
1267   - String charset = device.getCharset();
1268   - recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1269   - recordInfoXml.append("<Query>\r\n");
1270   - recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
1271   - recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
1272   - recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1273   - if (startTime != null) {
1274   - recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
1275   - }
1276   - if (endTime != null) {
1277   - recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
1278   - }
1279   - if (secrecy != null) {
1280   - recordInfoXml.append("<Secrecy> "+ secrecy + " </Secrecy>\r\n");
1281   - }
1282   - if (type != null) {
1283   - // 大华NVR要求必须增加一个值为all的文本元素节点Type
1284   - recordInfoXml.append("<Type>" + type+"</Type>\r\n");
1285   - }
1286   - recordInfoXml.append("</Query>\r\n");
1287   -
1288   - String tm = Long.toString(System.currentTimeMillis());
1289   -
1290   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1291   - : udpSipProvider.getNewCallId();
1292   -
1293   - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
1294   - "z9hG4bK-ViaRecordInfo-" + tm, "fromRec" + tm, null, callIdHeader);
1295   -
1296   - transmitRequest(device, request, errorEvent, okEvent);
1297   - } catch (SipException | ParseException | InvalidArgumentException e) {
1298   - e.printStackTrace();
1299   - return false;
1300   - }
1301   - return true;
1302   - }
1303   -
1304   - /**
1305   - * 查询报警信息
1306   - *
1307   - * @param device 视频设备
1308   - * @param startPriority 报警起始级别(可选)
1309   - * @param endPriority 报警终止级别(可选)
1310   - * @param alarmMethod 报警方式条件(可选)
1311   - * @param alarmType 报警类型
1312   - * @param startTime 报警发生起始时间(可选)
1313   - * @param endTime 报警发生终止时间(可选)
1314   - * @return true = 命令发送成功
1315   - */
1316   - @Override
1317   - public boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType,
1318   - String startTime, String endTime, SipSubscribe.Event errorEvent) {
1319   - try {
1320   - StringBuffer cmdXml = new StringBuffer(200);
1321   - String charset = device.getCharset();
1322   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1323   - cmdXml.append("<Query>\r\n");
1324   - cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
1325   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1326   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1327   - if (!StringUtils.isEmpty(startPriority)) {
1328   - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
1329   - }
1330   - if (!StringUtils.isEmpty(endPriority)) {
1331   - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
1332   - }
1333   - if (!StringUtils.isEmpty(alarmMethod)) {
1334   - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
1335   - }
1336   - if (!StringUtils.isEmpty(alarmType)) {
1337   - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
1338   - }
1339   - if (!StringUtils.isEmpty(startTime)) {
1340   - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
1341   - }
1342   - if (!StringUtils.isEmpty(endTime)) {
1343   - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
1344   - }
1345   - cmdXml.append("</Query>\r\n");
1346   -
1347   - String tm = Long.toString(System.currentTimeMillis());
1348   -
1349   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1350   - : udpSipProvider.getNewCallId();
1351   -
1352   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromAlarm" + tm, null, callIdHeader);
1353   - transmitRequest(device, request, errorEvent);
1354   - return true;
1355   - } catch (SipException | ParseException | InvalidArgumentException e) {
1356   - e.printStackTrace();
1357   - return false;
1358   - }
1359   - }
1360   -
1361   - /**
1362   - * 查询设备配置
1363   - *
1364   - * @param device 视频设备
1365   - * @param channelId 通道编码(可选)
1366   - * @param configType 配置类型:
1367   - */
1368   - @Override
1369   - public boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) {
1370   - try {
1371   - StringBuffer cmdXml = new StringBuffer(200);
1372   - String charset = device.getCharset();
1373   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1374   - cmdXml.append("<Query>\r\n");
1375   - cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
1376   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1377   - if (StringUtils.isEmpty(channelId)) {
1378   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1379   - } else {
1380   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1381   - }
1382   - cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n");
1383   - cmdXml.append("</Query>\r\n");
1384   -
1385   - String tm = Long.toString(System.currentTimeMillis());
1386   -
1387   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1388   - : udpSipProvider.getNewCallId();
1389   -
1390   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromConfig" + tm, null, callIdHeader);
1391   - transmitRequest(device, request, errorEvent);
1392   - return true;
1393   - } catch (SipException | ParseException | InvalidArgumentException e) {
1394   - e.printStackTrace();
1395   - return false;
1396   - }
1397   - }
1398   -
1399   - /**
1400   - * 查询设备预置位置
1401   - *
1402   - * @param device 视频设备
1403   - */
1404   - @Override
1405   - public boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) {
1406   - try {
1407   - StringBuffer cmdXml = new StringBuffer(200);
1408   - String charset = device.getCharset();
1409   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1410   - cmdXml.append("<Query>\r\n");
1411   - cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
1412   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1413   - if (StringUtils.isEmpty(channelId)) {
1414   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1415   - } else {
1416   - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1417   - }
1418   - cmdXml.append("</Query>\r\n");
1419   -
1420   - String tm = Long.toString(System.currentTimeMillis());
1421   -
1422   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1423   - : udpSipProvider.getNewCallId();
1424   -
1425   - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromConfig" + tm, null, callIdHeader);
1426   - transmitRequest(device, request, errorEvent);
1427   - return true;
1428   - } catch (SipException | ParseException | InvalidArgumentException e) {
1429   - e.printStackTrace();
1430   - return false;
1431   - }
1432   - }
1433   -
1434   - /**
1435   - * 查询移动设备位置数据
1436   - *
1437   - * @param device 视频设备
1438   - */
1439   - @Override
1440   - public boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) {
1441   - try {
1442   - StringBuffer mobilePostitionXml = new StringBuffer(200);
1443   - String charset = device.getCharset();
1444   - mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1445   - mobilePostitionXml.append("<Query>\r\n");
1446   - mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
1447   - mobilePostitionXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1448   - mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1449   - mobilePostitionXml.append("<Interval>60</Interval>\r\n");
1450   - mobilePostitionXml.append("</Query>\r\n");
1451   -
1452   - String tm = Long.toString(System.currentTimeMillis());
1453   -
1454   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1455   - : udpSipProvider.getNewCallId();
1456   -
1457   - Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, callIdHeader);
1458   -
1459   - transmitRequest(device, request, errorEvent);
1460   -
1461   - } catch (SipException | ParseException | InvalidArgumentException e) {
1462   - e.printStackTrace();
1463   - return false;
1464   - }
1465   - return true;
1466   - }
1467   -
1468   - /**
1469   - * 订阅、取消订阅移动位置
1470   - *
1471   - * @param device 视频设备
1472   - * @return true = 命令发送成功
1473   - */
1474   - @Override
1475   - public boolean mobilePositionSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) {
1476   - try {
1477   - StringBuffer subscribePostitionXml = new StringBuffer(200);
1478   - String charset = device.getCharset();
1479   - subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1480   - subscribePostitionXml.append("<Query>\r\n");
1481   - subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
1482   - subscribePostitionXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1483   - subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1484   - if (device.getSubscribeCycleForMobilePosition() > 0) {
1485   - subscribePostitionXml.append("<Interval>" + String.valueOf(device.getMobilePositionSubmissionInterval()) + "</Interval>\r\n");
1486   - }
1487   - subscribePostitionXml.append("</Query>\r\n");
1488   -
1489   - Request request;
1490   - if (dialog != null) {
1491   - SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
1492   - request = dialog.createRequest(Request.SUBSCRIBE);
1493   - ExpiresHeader expiresHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForCatalog());
1494   - request.setExpires(expiresHeader);
1495   -
1496   - request.setRequestURI(requestURI);
1497   -
1498   - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
1499   - request.setContent(subscribePostitionXml.toString(), contentTypeHeader);
1500   -
1501   - CSeqHeader cSeqHeader = (CSeqHeader)request.getHeader(CSeqHeader.NAME);
1502   - cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ(Request.SUBSCRIBE));
1503   - request.removeHeader(CSeqHeader.NAME);
1504   - request.addHeader(cSeqHeader);
1505   - }else {
1506   - String tm = Long.toString(System.currentTimeMillis());
1507   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1508   - : udpSipProvider.getNewCallId();
1509   - request = headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForMobilePosition(), "presence" ,callIdHeader); //Position;id=" + tm.substring(tm.length() - 4));
1510   - }
1511   - transmitRequest(device, request, errorEvent, okEvent);
1512   -
1513   - return true;
1514   -
1515   - } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
1516   - e.printStackTrace();
1517   - return false;
1518   - }
1519   - }
1520   -
1521   - /**
1522   - * 订阅、取消订阅报警信息
1523   - *
1524   - * @param device 视频设备
1525   - * @param expires 订阅过期时间(0 = 取消订阅)
1526   - * @param startPriority 报警起始级别(可选)
1527   - * @param endPriority 报警终止级别(可选)
1528   - * @param alarmMethod 报警方式条件(可选)
1529   - * @param alarmType 报警类型
1530   - * @param startTime 报警发生起始时间(可选)
1531   - * @param endTime 报警发生终止时间(可选)
1532   - * @return true = 命令发送成功
1533   - */
1534   - @Override
1535   - public boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) {
1536   - try {
1537   - StringBuffer cmdXml = new StringBuffer(200);
1538   - String charset = device.getCharset();
1539   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1540   - cmdXml.append("<Query>\r\n");
1541   - cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
1542   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1543   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1544   - if (!StringUtils.isEmpty(startPriority)) {
1545   - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
1546   - }
1547   - if (!StringUtils.isEmpty(endPriority)) {
1548   - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
1549   - }
1550   - if (!StringUtils.isEmpty(alarmMethod)) {
1551   - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
1552   - }
1553   - if (!StringUtils.isEmpty(alarmType)) {
1554   - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
1555   - }
1556   - if (!StringUtils.isEmpty(startTime)) {
1557   - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
1558   - }
1559   - if (!StringUtils.isEmpty(endTime)) {
1560   - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
1561   - }
1562   - cmdXml.append("</Query>\r\n");
1563   -
1564   - String tm = Long.toString(System.currentTimeMillis());
1565   -
1566   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1567   - : udpSipProvider.getNewCallId();
1568   -
1569   - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, expires, "presence" , callIdHeader);
1570   - transmitRequest(device, request);
1571   -
1572   - return true;
1573   -
1574   - } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
1575   - e.printStackTrace();
1576   - return false;
1577   - }
1578   - }
1579   -
1580   - @Override
1581   - public boolean catalogSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
1582   - try {
1583   - StringBuffer cmdXml = new StringBuffer(200);
1584   - String charset = device.getCharset();
1585   - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1586   - cmdXml.append("<Query>\r\n");
1587   - cmdXml.append("<CmdType>Catalog</CmdType>\r\n");
1588   - cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1589   - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1590   - cmdXml.append("</Query>\r\n");
1591   -
1592   -
1593   - Request request;
1594   - if (dialog != null) {
1595   - SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
1596   - request = dialog.createRequest(Request.SUBSCRIBE);
1597   - ExpiresHeader expiresHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForCatalog());
1598   - request.setExpires(expiresHeader);
1599   -
1600   - request.setRequestURI(requestURI);
1601   -
1602   - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
1603   - request.setContent(cmdXml.toString(), contentTypeHeader);
1604   -
1605   - CSeqHeader cSeqHeader = (CSeqHeader)request.getHeader(CSeqHeader.NAME);
1606   - cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ(Request.SUBSCRIBE));
1607   - request.removeHeader(CSeqHeader.NAME);
1608   - request.addHeader(cSeqHeader);
1609   -
1610   - }else {
1611   - String tm = Long.toString(System.currentTimeMillis());
1612   -
1613   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1614   - : udpSipProvider.getNewCallId();
1615   -
1616   - // 有效时间默认为60秒以上
1617   - request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
1618   - "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,
1619   - callIdHeader);
1620   -
1621   - }
1622   - transmitRequest(device, request, errorEvent, okEvent);
1623   - return true;
1624   -
1625   - } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
1626   - e.printStackTrace();
1627   - return false;
1628   - }
1629   - }
1630   -
1631   - @Override
1632   - public boolean dragZoomCmd(Device device, String channelId, String cmdString) {
1633   - try {
1634   - StringBuffer dragXml = new StringBuffer(200);
1635   - String charset = device.getCharset();
1636   - dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1637   - dragXml.append("<Control>\r\n");
1638   - dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");
1639   - dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
1640   - if (StringUtils.isEmpty(channelId)) {
1641   - dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1642   - } else {
1643   - dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
1644   - }
1645   - dragXml.append(cmdString);
1646   - dragXml.append("</Control>\r\n");
1647   - String tm = Long.toString(System.currentTimeMillis());
1648   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1649   - : udpSipProvider.getNewCallId();
1650   - Request request = headerProvider.createMessageRequest(device, dragXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
1651   - logger.debug("拉框信令: " + request.toString());
1652   - transmitRequest(device, request);
1653   - return true;
1654   - } catch (SipException | ParseException | InvalidArgumentException e) {
1655   - e.printStackTrace();
1656   - }
1657   - return false;
1658   - }
1659   -
1660   -
1661   - private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
1662   - return transmitRequest(device, request, null, null);
1663   - }
1664   -
1665   - private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent) throws SipException {
1666   - return transmitRequest(device, request, errorEvent, null);
1667   - }
1668   -
1669   - private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException {
1670   - ClientTransaction clientTransaction = null;
1671   - if("TCP".equals(device.getTransport())) {
1672   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1673   - } else if("UDP".equals(device.getTransport())) {
1674   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1675   - }
1676   - if (request.getHeader(UserAgentHeader.NAME) == null) {
1677   - List<String> agentParam = new ArrayList<>();
1678   - agentParam.add("wvp-pro");
1679   - // TODO 添加版本信息以及日期
1680   - UserAgentHeader userAgentHeader = null;
1681   - try {
1682   - userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
1683   - } catch (ParseException e) {
1684   - throw new RuntimeException(e);
1685   - }
1686   - request.addHeader(userAgentHeader);
1687   - }
1688   - CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
1689   - // 添加错误订阅
1690   - if (errorEvent != null) {
1691   - sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
1692   - errorEvent.response(eventResult);
1693   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
1694   - sipSubscribe.removeOkSubscribe(eventResult.callId);
1695   - }));
1696   - }
1697   - // 添加订阅
1698   - if (okEvent != null) {
1699   - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult ->{
1700   - okEvent.response(eventResult);
1701   - sipSubscribe.removeOkSubscribe(eventResult.callId);
1702   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
1703   - });
1704   - }
1705   -
1706   - clientTransaction.sendRequest();
1707   - return clientTransaction;
1708   - }
1709   -
1710   - /**
1711   - * 回放暂停
1712   - */
1713   - @Override
1714   - public void playPauseCmd(Device device, StreamInfo streamInfo) {
1715   - try {
1716   - Long cseq = redisCatchStorage.getCSEQ(Request.INFO);
1717   - StringBuffer content = new StringBuffer(200);
1718   - content.append("PAUSE RTSP/1.0\r\n");
1719   - content.append("CSeq: " + cseq + "\r\n");
1720   - content.append("PauseTime: now\r\n");
1721   - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
1722   - if (request == null) {
1723   - return;
1724   - }
1725   - logger.info(request.toString());
1726   - ClientTransaction clientTransaction = null;
1727   - if ("TCP".equals(device.getTransport())) {
1728   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1729   - } else if ("UDP".equals(device.getTransport())) {
1730   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1731   - }
1732   - if (clientTransaction != null) {
1733   - clientTransaction.sendRequest();
1734   - }
1735   -
1736   - } catch (SipException | ParseException | InvalidArgumentException e) {
1737   - e.printStackTrace();
1738   - }
1739   - }
1740   -
1741   - /**
1742   - * 回放恢复
1743   - */
1744   - @Override
1745   - public void playResumeCmd(Device device, StreamInfo streamInfo) {
1746   - try {
1747   - Long cseq = redisCatchStorage.getCSEQ(Request.INFO);
1748   - StringBuffer content = new StringBuffer(200);
1749   - content.append("PLAY RTSP/1.0\r\n");
1750   - content.append("CSeq: " + cseq + "\r\n");
1751   - content.append("Range: npt=now-\r\n");
1752   - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
1753   - if (request == null) {
1754   - return;
1755   - }
1756   - logger.info(request.toString());
1757   - ClientTransaction clientTransaction = null;
1758   - if ("TCP".equals(device.getTransport())) {
1759   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1760   - } else if ("UDP".equals(device.getTransport())) {
1761   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1762   - }
1763   -
1764   - clientTransaction.sendRequest();
1765   -
1766   - } catch (SipException | ParseException | InvalidArgumentException e) {
1767   - e.printStackTrace();
1768   - }
1769   - }
1770   -
1771   - /**
1772   - * 回放拖动播放
1773   - */
1774   - @Override
1775   - public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) {
1776   - try {
1777   - Long cseq = redisCatchStorage.getCSEQ(Request.INFO);
1778   - StringBuffer content = new StringBuffer(200);
1779   - content.append("PLAY RTSP/1.0\r\n");
1780   - content.append("CSeq: " + cseq + "\r\n");
1781   - content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");
1782   -
1783   - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
1784   - if (request == null) {
1785   - return;
1786   - }
1787   - logger.info(request.toString());
1788   - ClientTransaction clientTransaction = null;
1789   - if ("TCP".equals(device.getTransport())) {
1790   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1791   - } else if ("UDP".equals(device.getTransport())) {
1792   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1793   - }
1794   -
1795   - clientTransaction.sendRequest();
1796   -
1797   - } catch (SipException | ParseException | InvalidArgumentException e) {
1798   - e.printStackTrace();
1799   - }
1800   - }
1801   -
1802   - /**
1803   - * 回放倍速播放
1804   - */
1805   - @Override
1806   - public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) {
1807   - try {
1808   - Long cseq = redisCatchStorage.getCSEQ(Request.INFO);
1809   - StringBuffer content = new StringBuffer(200);
1810   - content.append("PLAY RTSP/1.0\r\n");
1811   - content.append("CSeq: " + cseq + "\r\n");
1812   - content.append("Scale: " + String.format("%.1f",speed) + "\r\n");
1813   - Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
1814   - if (request == null) {
1815   - return;
1816   - }
1817   - logger.info(request.toString());
1818   - ClientTransaction clientTransaction = null;
1819   - if ("TCP".equals(device.getTransport())) {
1820   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1821   - } else if ("UDP".equals(device.getTransport())) {
1822   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1823   - }
1824   -
1825   - clientTransaction.sendRequest();
1826   -
1827   - } catch (SipException | ParseException | InvalidArgumentException e) {
1828   - e.printStackTrace();
1829   - }
1830   - }
1831   -
1832   - @Override
1833   - public void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) {
1834   - try {
1835   - Request request = headerProvider.createInfoRequest(device, streamInfo, content);
1836   - if (request == null) {
1837   - return;
1838   - }
1839   - logger.info(request.toString());
1840   - ClientTransaction clientTransaction = null;
1841   - if ("TCP".equals(device.getTransport())) {
1842   - clientTransaction = tcpSipProvider.getNewClientTransaction(request);
1843   - } else if ("UDP".equals(device.getTransport())) {
1844   - clientTransaction = udpSipProvider.getNewClientTransaction(request);
1845   - }
1846   - CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
1847   - if(errorEvent != null) {
1848   - sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
1849   - errorEvent.response(eventResult);
1850   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
1851   - sipSubscribe.removeOkSubscribe(eventResult.callId);
1852   - }));
1853   - }
1854   -
1855   - if(okEvent != null) {
1856   - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
1857   - okEvent.response(eventResult);
1858   - sipSubscribe.removeOkSubscribe(eventResult.callId);
1859   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
1860   - });
1861   - }
1862   - clientTransaction.sendRequest();
1863   -
1864   - } catch (SipException | ParseException | InvalidArgumentException e) {
1865   - e.printStackTrace();
1866   - }
1867   - }
1868   -
1869   - @Override
1870   - public boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) {
1871   - if (device == null) {
1872   - return false;
1873   - }
1874   - logger.info("[发送 报警通知] {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(),
1875   - deviceAlarm.getLongitude(), deviceAlarm.getLatitude());
1876   - try {
1877   - String characterSet = device.getCharset();
1878   - StringBuffer deviceStatusXml = new StringBuffer(600);
1879   - deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
1880   - deviceStatusXml.append("<Notify>\r\n");
1881   - deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n");
1882   - deviceStatusXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
1883   - deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n");
1884   - deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n");
1885   - deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n");
1886   - deviceStatusXml.append("<AlarmTime>" + deviceAlarm.getAlarmTime() + "</AlarmTime>\r\n");
1887   - deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n");
1888   - deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n");
1889   - deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n");
1890   - deviceStatusXml.append("<info>\r\n");
1891   - deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n");
1892   - deviceStatusXml.append("</info>\r\n");
1893   - deviceStatusXml.append("</Notify>\r\n");
1894   -
1895   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1896   - : udpSipProvider.getNewCallId();
1897   - String tm = Long.toString(System.currentTimeMillis());
1898   - Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
1899   - transmitRequest(device, request);
1900   -
1901   -
1902   - } catch (SipException | ParseException e) {
1903   - e.printStackTrace();
1904   - return false;
1905   - } catch (InvalidArgumentException e) {
1906   - throw new RuntimeException(e);
1907   - }
1908   - return true;
1909   - }
1910   -
1911   - private void sendNotify(Device device, String catalogXmlContent,
1912   - SubscribeInfo subscribeInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent )
1913   - throws NoSuchFieldException, IllegalAccessException, SipException, ParseException {
1914   - MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory();
1915   - String characterSet = device.getCharset();
1916   - // 设置编码, 防止中文乱码
1917   - messageFactory.setDefaultContentEncodingCharset(characterSet);
1918   - Dialog dialog = subscribeInfo.getDialog();
1919   - if (dialog == null || !dialog.getState().equals(DialogState.CONFIRMED)) {
1920   - return;
1921   - }
1922   - SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY);
1923   - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
1924   - notifyRequest.setContent(catalogXmlContent, contentTypeHeader);
1925   -
1926   - SubscriptionStateHeader subscriptionState = sipFactory.createHeaderFactory()
1927   - .createSubscriptionStateHeader(SubscriptionStateHeader.ACTIVE);
1928   - notifyRequest.addHeader(subscriptionState);
1929   -
1930   - EventHeader event = sipFactory.createHeaderFactory().createEventHeader(subscribeInfo.getEventType());
1931   - if (subscribeInfo.getEventId() != null) {
1932   - event.setEventId(subscribeInfo.getEventId());
1933   - }
1934   - notifyRequest.addHeader(event);
1935   -
1936   - SipURI sipURI = (SipURI) notifyRequest.getRequestURI();
1937   - if (subscribeInfo.getTransaction() != null) {
1938   - SIPRequest request = (SIPRequest) subscribeInfo.getTransaction().getRequest();
1939   - sipURI.setHost(request.getRemoteAddress().getHostAddress());
1940   - sipURI.setPort(request.getRemotePort());
1941   - }else {
1942   - sipURI.setHost(device.getIp());
1943   - sipURI.setPort(device.getPort());
1944   - }
1945   -
1946   - ClientTransaction transaction = null;
1947   - if ("TCP".equals(device.getTransport())) {
1948   - transaction = tcpSipProvider.getNewClientTransaction(notifyRequest);
1949   - } else if ("UDP".equals(device.getTransport())) {
1950   - transaction = udpSipProvider.getNewClientTransaction(notifyRequest);
1951   - }
1952   - // 添加错误订阅
1953   - if (errorEvent != null) {
1954   - sipSubscribe.addErrorSubscribe(subscribeInfo.getCallId(), errorEvent);
1955   - }
1956   - // 添加订阅
1957   - if (okEvent != null) {
1958   - sipSubscribe.addOkSubscribe(subscribeInfo.getCallId(), okEvent);
1959   - }
1960   - if (transaction == null) {
1961   - logger.error("平台{}的Transport错误:{}",device.getDeviceId(), device.getTransport());
1962   - return;
1963   - }
1964   - dialog.sendRequest(transaction);
1965   -
1966   - }
1967   -}
  1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.common.StreamInfo;
  5 +import com.genersoft.iot.vmp.conf.DynamicTask;
  6 +import com.genersoft.iot.vmp.conf.SipConfig;
  7 +import com.genersoft.iot.vmp.conf.UserSetting;
  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.VideoStreamSessionManager;
  11 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
  12 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
  13 +import com.genersoft.iot.vmp.utils.DateUtil;
  14 +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
  15 +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  16 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  17 +import com.genersoft.iot.vmp.service.IMediaServerService;
  18 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  19 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  20 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  21 +import gov.nist.javax.sip.SipProviderImpl;
  22 +import gov.nist.javax.sip.SipStackImpl;
  23 +import gov.nist.javax.sip.message.MessageFactoryImpl;
  24 +import gov.nist.javax.sip.message.SIPRequest;
  25 +import gov.nist.javax.sip.stack.SIPDialog;
  26 +import org.slf4j.Logger;
  27 +import org.slf4j.LoggerFactory;
  28 +import org.springframework.beans.factory.annotation.Autowired;
  29 +import org.springframework.beans.factory.annotation.Qualifier;
  30 +import org.springframework.context.annotation.DependsOn;
  31 +import org.springframework.stereotype.Component;
  32 +import org.springframework.util.StringUtils;
  33 +
  34 +import javax.sip.*;
  35 +import javax.sip.address.Address;
  36 +import javax.sip.address.SipURI;
  37 +import javax.sip.address.URI;
  38 +import javax.sip.header.*;
  39 +import javax.sip.message.Request;
  40 +import java.lang.reflect.Field;
  41 +import java.text.ParseException;
  42 +import java.util.ArrayList;
  43 +import java.util.HashSet;
  44 +import java.util.List;
  45 +
  46 +/**
  47 + * @description:设备能力接口,用于定义设备的控制、查询能力
  48 + * @author: swwheihei
  49 + * @date: 2020年5月3日 下午9:22:48
  50 + */
  51 +@Component
  52 +@DependsOn("sipLayer")
  53 +public class SIPCommander implements ISIPCommander {
  54 +
  55 + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
  56 +
  57 + @Autowired
  58 + private SipConfig sipConfig;
  59 +
  60 + @Autowired
  61 + private SipFactory sipFactory;
  62 +
  63 + @Autowired
  64 + @Qualifier(value="tcpSipProvider")
  65 + private SipProviderImpl tcpSipProvider;
  66 +
  67 + @Autowired
  68 + @Qualifier(value="udpSipProvider")
  69 + private SipProviderImpl udpSipProvider;
  70 +
  71 + @Autowired
  72 + private SIPRequestHeaderProvider headerProvider;
  73 +
  74 + @Autowired
  75 + private VideoStreamSessionManager streamSession;
  76 +
  77 + @Autowired
  78 + private IVideoManagerStorage storager;
  79 +
  80 + @Autowired
  81 + private IRedisCatchStorage redisCatchStorage;
  82 +
  83 + @Autowired
  84 + private UserSetting userSetting;
  85 +
  86 + @Autowired
  87 + private ZLMHttpHookSubscribe subscribe;
  88 +
  89 + @Autowired
  90 + private SipSubscribe sipSubscribe;
  91 +
  92 + @Autowired
  93 + private IMediaServerService mediaServerService;
  94 +
  95 + @Autowired
  96 + private DynamicTask dynamicTask;
  97 +
  98 +
  99 + /**
  100 + * 云台方向放控制,使用配置文件中的默认镜头移动速度
  101 + *
  102 + * @param device 控制设备
  103 + * @param channelId 预览通道
  104 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  105 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  106 + */
  107 + @Override
  108 + public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) {
  109 + return ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0);
  110 + }
  111 +
  112 + /**
  113 + * 云台方向放控制
  114 + *
  115 + * @param device 控制设备
  116 + * @param channelId 预览通道
  117 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  118 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  119 + * @param moveSpeed 镜头移动速度
  120 + */
  121 + @Override
  122 + public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) {
  123 + return ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0);
  124 + }
  125 +
  126 + /**
  127 + * 云台缩放控制,使用配置文件中的默认镜头缩放速度
  128 + *
  129 + * @param device 控制设备
  130 + * @param channelId 预览通道
  131 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  132 + */
  133 + @Override
  134 + public boolean ptzZoomCmd(Device device, String channelId, int inOut) {
  135 + return ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed());
  136 + }
  137 +
  138 + /**
  139 + * 云台缩放控制
  140 + *
  141 + * @param device 控制设备
  142 + * @param channelId 预览通道
  143 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  144 + * @param zoomSpeed 镜头缩放速度
  145 + */
  146 + @Override
  147 + public boolean ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) {
  148 + return ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed);
  149 + }
  150 +
  151 + /**
  152 + * 云台指令码计算
  153 + *
  154 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  155 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  156 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  157 + * @param moveSpeed 镜头移动速度 默认 0XFF (0-255)
  158 + * @param zoomSpeed 镜头缩放速度 默认 0X1 (0-255)
  159 + */
  160 + public static String cmdString(int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) {
  161 + int cmdCode = 0;
  162 + if (leftRight == 2) {
  163 + cmdCode|=0x01; // 右移
  164 + } else if(leftRight == 1) {
  165 + cmdCode|=0x02; // 左移
  166 + }
  167 + if (upDown == 2) {
  168 + cmdCode|=0x04; // 下移
  169 + } else if(upDown == 1) {
  170 + cmdCode|=0x08; // 上移
  171 + }
  172 + if (inOut == 2) {
  173 + cmdCode |= 0x10; // 放大
  174 + } else if(inOut == 1) {
  175 + cmdCode |= 0x20; // 缩小
  176 + }
  177 + StringBuilder builder = new StringBuilder("A50F01");
  178 + String strTmp;
  179 + strTmp = String.format("%02X", cmdCode);
  180 + builder.append(strTmp, 0, 2);
  181 + strTmp = String.format("%02X", moveSpeed);
  182 + builder.append(strTmp, 0, 2);
  183 + builder.append(strTmp, 0, 2);
  184 + strTmp = String.format("%X", zoomSpeed);
  185 + builder.append(strTmp, 0, 1).append("0");
  186 + //计算校验码
  187 + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + moveSpeed + moveSpeed + (zoomSpeed /*<< 4*/ & 0XF0)) % 0X100;
  188 + strTmp = String.format("%02X", checkCode);
  189 + builder.append(strTmp, 0, 2);
  190 + return builder.toString();
  191 +}
  192 +
  193 + /**
  194 + * 云台指令码计算
  195 + *
  196 + * @param cmdCode 指令码
  197 + * @param parameter1 数据1
  198 + * @param parameter2 数据2
  199 + * @param combineCode2 组合码2
  200 + */
  201 + public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {
  202 + StringBuilder builder = new StringBuilder("A50F01");
  203 + String strTmp;
  204 + strTmp = String.format("%02X", cmdCode);
  205 + builder.append(strTmp, 0, 2);
  206 + strTmp = String.format("%02X", parameter1);
  207 + builder.append(strTmp, 0, 2);
  208 + strTmp = String.format("%02X", parameter2);
  209 + builder.append(strTmp, 0, 2);
  210 + strTmp = String.format("%X", combineCode2);
  211 + builder.append(strTmp, 0, 1).append("0");
  212 + //计算校验码
  213 + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;
  214 + strTmp = String.format("%02X", checkCode);
  215 + builder.append(strTmp, 0, 2);
  216 + return builder.toString();
  217 + }
  218 +
  219 + /**
  220 + * 云台控制,支持方向与缩放控制
  221 + *
  222 + * @param device 控制设备
  223 + * @param channelId 预览通道
  224 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  225 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  226 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  227 + * @param moveSpeed 镜头移动速度
  228 + * @param zoomSpeed 镜头缩放速度
  229 + */
  230 + @Override
  231 + public boolean ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,
  232 + int zoomSpeed) {
  233 + try {
  234 + String cmdStr= cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed);
  235 + StringBuffer ptzXml = new StringBuffer(200);
  236 + String charset = device.getCharset();
  237 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  238 + ptzXml.append("<Control>\r\n");
  239 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  240 + ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  241 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  242 + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
  243 + ptzXml.append("<Info>\r\n");
  244 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  245 + ptzXml.append("</Info>\r\n");
  246 + ptzXml.append("</Control>\r\n");
  247 +
  248 + String tm = Long.toString(System.currentTimeMillis());
  249 +
  250 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  251 + : udpSipProvider.getNewCallId();
  252 +
  253 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
  254 +
  255 + transmitRequest(device, request);
  256 + return true;
  257 + } catch (SipException | ParseException | InvalidArgumentException e) {
  258 + e.printStackTrace();
  259 + }
  260 + return false;
  261 + }
  262 +
  263 + /**
  264 + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
  265 + *
  266 + * @param device 控制设备
  267 + * @param channelId 预览通道
  268 + * @param cmdCode 指令码
  269 + * @param parameter1 数据1
  270 + * @param parameter2 数据2
  271 + * @param combineCode2 组合码2
  272 + */
  273 + @Override
  274 + public boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) {
  275 + try {
  276 + String cmdStr= frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);
  277 + logger.debug("控制字符串:" + cmdStr);
  278 + StringBuffer ptzXml = new StringBuffer(200);
  279 + String charset = device.getCharset();
  280 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  281 + ptzXml.append("<Control>\r\n");
  282 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  283 + ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  284 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  285 + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
  286 + ptzXml.append("<Info>\r\n");
  287 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  288 + ptzXml.append("</Info>\r\n");
  289 + ptzXml.append("</Control>\r\n");
  290 +
  291 + String tm = Long.toString(System.currentTimeMillis());
  292 +
  293 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  294 + : udpSipProvider.getNewCallId();
  295 +
  296 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
  297 + transmitRequest(device, request);
  298 + return true;
  299 + } catch (SipException | ParseException | InvalidArgumentException e) {
  300 + e.printStackTrace();
  301 + }
  302 + return false;
  303 + }
  304 +
  305 + /**
  306 + * 前端控制指令(用于转发上级指令)
  307 + * @param device 控制设备
  308 + * @param channelId 预览通道
  309 + * @param cmdString 前端控制指令串
  310 + */
  311 + @Override
  312 + public boolean fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) {
  313 + try {
  314 + StringBuffer ptzXml = new StringBuffer(200);
  315 + String charset = device.getCharset();
  316 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  317 + ptzXml.append("<Control>\r\n");
  318 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  319 + ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  320 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  321 + ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n");
  322 + ptzXml.append("<Info>\r\n");
  323 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  324 + ptzXml.append("</Info>\r\n");
  325 + ptzXml.append("</Control>\r\n");
  326 +
  327 + String tm = Long.toString(System.currentTimeMillis());
  328 +
  329 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  330 + : udpSipProvider.getNewCallId();
  331 +
  332 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
  333 + transmitRequest(device, request, errorEvent, okEvent);
  334 + return true;
  335 + } catch (SipException | ParseException | InvalidArgumentException e) {
  336 + e.printStackTrace();
  337 + }
  338 + return false;
  339 + }
  340 +
  341 + /**
  342 + * 请求预览视频流
  343 + * @param device 视频设备
  344 + * @param channelId 预览通道
  345 + * @param event hook订阅
  346 + * @param errorEvent sip错误订阅
  347 + */
  348 + @Override
  349 + public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  350 + ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
  351 + String streamId = ssrcInfo.getStream();
  352 + try {
  353 + if (device == null) {
  354 + return;
  355 + }
  356 + String streamMode = device.getStreamMode().toUpperCase();
  357 +
  358 + logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  359 + // 添加订阅
  360 + JSONObject subscribeKey = new JSONObject();
  361 + subscribeKey.put("app", "rtp");
  362 + subscribeKey.put("stream", streamId);
  363 + subscribeKey.put("regist", true);
  364 + subscribeKey.put("schema", "rtmp");
  365 + subscribeKey.put("mediaServerId", mediaServerItem.getId());
  366 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  367 + (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  368 + if (event != null) {
  369 + event.response(mediaServerItemInUse, json);
  370 + }
  371 + });
  372 + //
  373 + StringBuffer content = new StringBuffer(200);
  374 + content.append("v=0\r\n");
  375 + content.append("o="+ channelId+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
  376 + content.append("s=Play\r\n");
  377 + content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
  378 + content.append("t=0 0\r\n");
  379 +
  380 + if (userSetting.isSeniorSdp()) {
  381 + if("TCP-PASSIVE".equals(streamMode)) {
  382 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  383 + }else if ("TCP-ACTIVE".equals(streamMode)) {
  384 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  385 + }else if("UDP".equals(streamMode)) {
  386 + content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
  387 + }
  388 + content.append("a=recvonly\r\n");
  389 + content.append("a=rtpmap:96 PS/90000\r\n");
  390 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  391 + content.append("a=rtpmap:126 H264/90000\r\n");
  392 + content.append("a=rtpmap:125 H264S/90000\r\n");
  393 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  394 + content.append("a=rtpmap:99 H265/90000\r\n");
  395 + content.append("a=rtpmap:98 H264/90000\r\n");
  396 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  397 + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
  398 + content.append("a=setup:passive\r\n");
  399 + content.append("a=connection:new\r\n");
  400 + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  401 + content.append("a=setup:active\r\n");
  402 + content.append("a=connection:new\r\n");
  403 + }
  404 + }else {
  405 + if("TCP-PASSIVE".equals(streamMode)) {
  406 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
  407 + }else if ("TCP-ACTIVE".equals(streamMode)) {
  408 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
  409 + }else if("UDP".equals(streamMode)) {
  410 + content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
  411 + }
  412 + content.append("a=recvonly\r\n");
  413 + content.append("a=rtpmap:96 PS/90000\r\n");
  414 + content.append("a=rtpmap:98 H264/90000\r\n");
  415 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  416 + content.append("a=rtpmap:99 H265/90000\r\n");
  417 + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
  418 + content.append("a=setup:passive\r\n");
  419 + content.append("a=connection:new\r\n");
  420 + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  421 + content.append("a=setup:active\r\n");
  422 + content.append("a=connection:new\r\n");
  423 + }
  424 + }
  425 +
  426 + content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc
  427 + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
  428 +// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备
  429 +
  430 + String tm = Long.toString(System.currentTimeMillis());
  431 +
  432 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  433 + : udpSipProvider.getNewCallId();
  434 +
  435 + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrcInfo.getSsrc(), callIdHeader);
  436 +
  437 + transmitRequest(device, request, (e -> {
  438 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  439 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  440 + errorEvent.response(e);
  441 + }), e ->{
  442 + // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
  443 + streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play);
  444 + streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog);
  445 + okEvent.response(e);
  446 + });
  447 +
  448 +
  449 + } catch ( SipException | ParseException | InvalidArgumentException e) {
  450 + e.printStackTrace();
  451 + }
  452 + }
  453 +
  454 + /**
  455 + * 请求回放视频流
  456 + *
  457 + * @param device 视频设备
  458 + * @param channelId 预览通道
  459 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  460 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  461 + */
  462 + @Override
  463 + public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  464 + String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  465 + SipSubscribe.Event errorEvent) {
  466 + try {
  467 +
  468 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  469 +
  470 + StringBuffer content = new StringBuffer(200);
  471 + content.append("v=0\r\n");
  472 + content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  473 + content.append("s=Playback\r\n");
  474 + content.append("u="+channelId+":0\r\n");
  475 + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  476 + content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
  477 + +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
  478 +
  479 + String streamMode = device.getStreamMode().toUpperCase();
  480 +
  481 + if (userSetting.isSeniorSdp()) {
  482 + if("TCP-PASSIVE".equals(streamMode)) {
  483 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  484 + }else if ("TCP-ACTIVE".equals(streamMode)) {
  485 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  486 + }else if("UDP".equals(streamMode)) {
  487 + content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
  488 + }
  489 + content.append("a=recvonly\r\n");
  490 + content.append("a=rtpmap:96 PS/90000\r\n");
  491 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  492 + content.append("a=rtpmap:126 H264/90000\r\n");
  493 + content.append("a=rtpmap:125 H264S/90000\r\n");
  494 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  495 + content.append("a=rtpmap:99 H265/90000\r\n");
  496 + content.append("a=rtpmap:98 H264/90000\r\n");
  497 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  498 + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
  499 + content.append("a=setup:passive\r\n");
  500 + content.append("a=connection:new\r\n");
  501 + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  502 + content.append("a=setup:active\r\n");
  503 + content.append("a=connection:new\r\n");
  504 + }
  505 + }else {
  506 + if("TCP-PASSIVE".equals(streamMode)) {
  507 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
  508 + }else if ("TCP-ACTIVE".equals(streamMode)) {
  509 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
  510 + }else if("UDP".equals(streamMode)) {
  511 + content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
  512 + }
  513 + content.append("a=recvonly\r\n");
  514 + content.append("a=rtpmap:96 PS/90000\r\n");
  515 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  516 + content.append("a=rtpmap:98 H264/90000\r\n");
  517 + content.append("a=rtpmap:99 H265/90000\r\n");
  518 + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
  519 + content.append("a=setup:passive\r\n");
  520 + content.append("a=connection:new\r\n");
  521 + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  522 + content.append("a=setup:active\r\n");
  523 + content.append("a=connection:new\r\n");
  524 + }
  525 + }
  526 +
  527 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  528 +
  529 + String tm = Long.toString(System.currentTimeMillis());
  530 +
  531 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  532 + : udpSipProvider.getNewCallId();
  533 +
  534 + // 添加订阅
  535 + JSONObject subscribeKey = new JSONObject();
  536 + subscribeKey.put("app", "rtp");
  537 + subscribeKey.put("stream", ssrcInfo.getStream());
  538 + subscribeKey.put("regist", true);
  539 + subscribeKey.put("schema", "rtmp");
  540 + subscribeKey.put("mediaServerId", mediaServerItem.getId());
  541 + logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey);
  542 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  543 + (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  544 + if (hookEvent != null) {
  545 + InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream());
  546 + hookEvent.call(inviteStreamInfo);
  547 + }
  548 + });
  549 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
  550 +
  551 + transmitRequest(device, request, errorEvent, okEvent -> {
  552 + ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
  553 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.playback);
  554 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
  555 + });
  556 + if (inviteStreamCallback != null) {
  557 + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
  558 + }
  559 + } catch ( SipException | ParseException | InvalidArgumentException e) {
  560 + e.printStackTrace();
  561 + }
  562 + }
  563 +
  564 + /**
  565 + * 请求历史媒体下载
  566 + *
  567 + * @param device 视频设备
  568 + * @param channelId 预览通道
  569 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  570 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  571 + * @param downloadSpeed 下载倍速参数
  572 + */
  573 + @Override
  574 + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  575 + String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  576 + SipSubscribe.Event errorEvent) {
  577 + try {
  578 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  579 +
  580 + StringBuffer content = new StringBuffer(200);
  581 + content.append("v=0\r\n");
  582 + content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  583 + content.append("s=Download\r\n");
  584 + content.append("u="+channelId+":0\r\n");
  585 + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  586 + content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
  587 + +DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
  588 +
  589 + String streamMode = device.getStreamMode().toUpperCase();
  590 +
  591 + if (userSetting.isSeniorSdp()) {
  592 + if("TCP-PASSIVE".equals(streamMode)) {
  593 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  594 + }else if ("TCP-ACTIVE".equals(streamMode)) {
  595 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  596 + }else if("UDP".equals(streamMode)) {
  597 + content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
  598 + }
  599 + content.append("a=recvonly\r\n");
  600 + content.append("a=rtpmap:96 PS/90000\r\n");
  601 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  602 + content.append("a=rtpmap:126 H264/90000\r\n");
  603 + content.append("a=rtpmap:125 H264S/90000\r\n");
  604 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  605 + content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
  606 + content.append("a=fmtp:99 profile-level-id=3\r\n");
  607 + content.append("a=rtpmap:98 H264/90000\r\n");
  608 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  609 + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
  610 + content.append("a=setup:passive\r\n");
  611 + content.append("a=connection:new\r\n");
  612 + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  613 + content.append("a=setup:active\r\n");
  614 + content.append("a=connection:new\r\n");
  615 + }
  616 + }else {
  617 + if("TCP-PASSIVE".equals(streamMode)) {
  618 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
  619 + }else if ("TCP-ACTIVE".equals(streamMode)) {
  620 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
  621 + }else if("UDP".equals(streamMode)) {
  622 + content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
  623 + }
  624 + content.append("a=recvonly\r\n");
  625 + content.append("a=rtpmap:96 PS/90000\r\n");
  626 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  627 + content.append("a=rtpmap:98 H264/90000\r\n");
  628 + content.append("a=rtpmap:99 H265/90000\r\n");
  629 + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
  630 + content.append("a=setup:passive\r\n");
  631 + content.append("a=connection:new\r\n");
  632 + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  633 + content.append("a=setup:active\r\n");
  634 + content.append("a=connection:new\r\n");
  635 + }
  636 + }
  637 + content.append("a=downloadspeed:" + downloadSpeed + "\r\n");
  638 +
  639 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  640 +
  641 + String tm = Long.toString(System.currentTimeMillis());
  642 +
  643 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  644 + : udpSipProvider.getNewCallId();
  645 +
  646 + // 添加订阅
  647 + JSONObject subscribeKey = new JSONObject();
  648 + subscribeKey.put("app", "rtp");
  649 + subscribeKey.put("stream", ssrcInfo.getStream());
  650 + subscribeKey.put("regist", true);
  651 + subscribeKey.put("mediaServerId", mediaServerItem.getId());
  652 + logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
  653 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  654 + (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  655 + hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
  656 + subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
  657 + subscribeKey.put("regist", false);
  658 + subscribeKey.put("schema", "rtmp");
  659 + // 添加流注销的订阅,注销了后向设备发送bye
  660 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  661 + (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd)->{
  662 + ClientTransaction transaction = streamSession.getTransaction(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
  663 + if (transaction != null) {
  664 + logger.info("[录像]下载结束, 发送BYE");
  665 + streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
  666 + }
  667 + });
  668 + });
  669 +
  670 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
  671 + if (inviteStreamCallback != null) {
  672 + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
  673 + }
  674 + transmitRequest(device, request, errorEvent, okEvent->{
  675 + ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
  676 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.download);
  677 + streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
  678 + });
  679 +
  680 +
  681 + } catch ( SipException | ParseException | InvalidArgumentException e) {
  682 + e.printStackTrace();
  683 + }
  684 + }
  685 +
  686 + /**
  687 + * 视频流停止, 不使用回调
  688 + */
  689 + @Override
  690 + public void streamByeCmd(String deviceId, String channelId, String stream, String callId) {
  691 + streamByeCmd(deviceId, channelId, stream, callId, null);
  692 + }
  693 +
  694 + /**
  695 + * 视频流停止
  696 + */
  697 + @Override
  698 + public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) {
  699 + try {
  700 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, callId, stream);
  701 + ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId, stream, callId);
  702 +
  703 + if (transaction == null ) {
  704 + logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
  705 + SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
  706 + if (okEvent != null) {
  707 + okEvent.response(eventResult);
  708 + }
  709 + return;
  710 + }
  711 + SIPDialog dialog;
  712 + if (callId != null) {
  713 + dialog = streamSession.getDialogByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), callId);
  714 + }else {
  715 + if (stream == null && ssrcTransaction == null && ssrcTransaction.getStream() == null) {
  716 + return;
  717 + }
  718 + dialog = streamSession.getDialogByStream(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  719 + }
  720 + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());
  721 + mediaServerService.closeRTPServer(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  722 + streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  723 +
  724 + if (dialog == null) {
  725 + logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId());
  726 + return;
  727 + }
  728 + SipStack sipStack = udpSipProvider.getSipStack();
  729 + SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog);
  730 + if (dialog != sipDialog) {
  731 + dialog = sipDialog;
  732 + }else {
  733 + dialog.setSipProvider(udpSipProvider);
  734 + try {
  735 + Field sipStackField = SIPDialog.class.getDeclaredField("sipStack");
  736 + sipStackField.setAccessible(true);
  737 + sipStackField.set(dialog, sipStack);
  738 + Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners");
  739 + eventListenersField.setAccessible(true);
  740 + eventListenersField.set(dialog, new HashSet<>());
  741 + } catch (NoSuchFieldException | IllegalAccessException e) {
  742 + e.printStackTrace();
  743 + }
  744 + }
  745 +
  746 + Request byeRequest = dialog.createRequest(Request.BYE);
  747 + SipURI byeURI = (SipURI) byeRequest.getRequestURI();
  748 + SIPRequest request = (SIPRequest)transaction.getRequest();
  749 + byeURI.setHost(request.getRemoteAddress().getHostAddress());
  750 + byeURI.setPort(request.getRemotePort());
  751 + ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME);
  752 + String protocol = viaHeader.getTransport().toUpperCase();
  753 + ClientTransaction clientTransaction = null;
  754 + if("TCP".equals(protocol)) {
  755 + clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest);
  756 + } else if("UDP".equals(protocol)) {
  757 + clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
  758 + }
  759 +
  760 + CallIdHeader callIdHeader = (CallIdHeader) byeRequest.getHeader(CallIdHeader.NAME);
  761 + if (okEvent != null) {
  762 + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);
  763 + }
  764 +
  765 + dialog.sendRequest(clientTransaction);
  766 +
  767 + } catch (SipException | ParseException e) {
  768 + e.printStackTrace();
  769 + }
  770 + }
  771 +
  772 + /**
  773 + * 语音广播
  774 + *
  775 + * @param device 视频设备
  776 + * @param channelId 预览通道
  777 + */
  778 + @Override
  779 + public boolean audioBroadcastCmd(Device device, String channelId) {
  780 + // 改为新的实现
  781 + return false;
  782 + }
  783 +
  784 + /**
  785 + * 语音广播
  786 + *
  787 + * @param device 视频设备
  788 + */
  789 + @Override
  790 + public boolean audioBroadcastCmd(Device device) {
  791 + try {
  792 + StringBuffer broadcastXml = new StringBuffer(200);
  793 + String charset = device.getCharset();
  794 + broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  795 + broadcastXml.append("<Notify>\r\n");
  796 + broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
  797 + broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  798 + broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
  799 + broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
  800 + broadcastXml.append("</Notify>\r\n");
  801 +
  802 + String tm = Long.toString(System.currentTimeMillis());
  803 +
  804 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  805 + : udpSipProvider.getNewCallId();
  806 +
  807 + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), "z9hG4bK-ViaBcst-" + tm, "FromBcst" + tm, null, callIdHeader);
  808 + transmitRequest(device, request);
  809 + return true;
  810 + } catch (SipException | ParseException | InvalidArgumentException e) {
  811 + e.printStackTrace();
  812 + }
  813 + return false;
  814 + }
  815 + @Override
  816 + public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) {
  817 + try {
  818 + StringBuffer broadcastXml = new StringBuffer(200);
  819 + String charset = device.getCharset();
  820 + broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  821 + broadcastXml.append("<Notify>\r\n");
  822 + broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
  823 + broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  824 + broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
  825 + broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
  826 + broadcastXml.append("</Notify>\r\n");
  827 +
  828 + String tm = Long.toString(System.currentTimeMillis());
  829 +
  830 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  831 + : udpSipProvider.getNewCallId();
  832 +
  833 + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), "z9hG4bK-ViaBcst-" + tm, "FromBcst" + tm, null, callIdHeader);
  834 + transmitRequest(device, request, errorEvent);
  835 + } catch (SipException | ParseException | InvalidArgumentException e) {
  836 + e.printStackTrace();
  837 + }
  838 + }
  839 +
  840 +
  841 + /**
  842 + * 音视频录像控制
  843 + *
  844 + * @param device 视频设备
  845 + * @param channelId 预览通道
  846 + * @param recordCmdStr 录像命令:Record / StopRecord
  847 + */
  848 + @Override
  849 + public boolean recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) {
  850 + try {
  851 + StringBuffer cmdXml = new StringBuffer(200);
  852 + String charset = device.getCharset();
  853 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  854 + cmdXml.append("<Control>\r\n");
  855 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  856 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  857 + if (StringUtils.isEmpty(channelId)) {
  858 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  859 + } else {
  860 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  861 + }
  862 + cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n");
  863 + cmdXml.append("</Control>\r\n");
  864 +
  865 + String tm = Long.toString(System.currentTimeMillis());
  866 +
  867 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  868 + : udpSipProvider.getNewCallId();
  869 +
  870 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromRecord" + tm, null, callIdHeader);
  871 + transmitRequest(device, request, errorEvent);
  872 + return true;
  873 + } catch (SipException | ParseException | InvalidArgumentException e) {
  874 + e.printStackTrace();
  875 + return false;
  876 + }
  877 + }
  878 +
  879 + /**
  880 + * 远程启动控制命令
  881 + *
  882 + * @param device 视频设备
  883 + */
  884 + @Override
  885 + public boolean teleBootCmd(Device device) {
  886 + try {
  887 + StringBuffer cmdXml = new StringBuffer(200);
  888 + String charset = device.getCharset();
  889 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  890 + cmdXml.append("<Control>\r\n");
  891 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  892 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  893 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  894 + cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n");
  895 + cmdXml.append("</Control>\r\n");
  896 +
  897 + String tm = Long.toString(System.currentTimeMillis());
  898 +
  899 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  900 + : udpSipProvider.getNewCallId();
  901 +
  902 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromBoot" + tm, null, callIdHeader);
  903 + transmitRequest(device, request);
  904 + return true;
  905 + } catch (SipException | ParseException | InvalidArgumentException e) {
  906 + e.printStackTrace();
  907 + return false;
  908 + }
  909 + }
  910 +
  911 + /**
  912 + * 报警布防/撤防命令
  913 + *
  914 + * @param device 视频设备
  915 + * @param guardCmdStr "SetGuard"/"ResetGuard"
  916 + */
  917 + @Override
  918 + public boolean guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) {
  919 + try {
  920 + StringBuffer cmdXml = new StringBuffer(200);
  921 + String charset = device.getCharset();
  922 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  923 + cmdXml.append("<Control>\r\n");
  924 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  925 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  926 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  927 + cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");
  928 + cmdXml.append("</Control>\r\n");
  929 +
  930 + String tm = Long.toString(System.currentTimeMillis());
  931 +
  932 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  933 + : udpSipProvider.getNewCallId();
  934 +
  935 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromGuard" + tm, null, callIdHeader);
  936 + transmitRequest(device, request, errorEvent);
  937 + return true;
  938 + } catch (SipException | ParseException | InvalidArgumentException e) {
  939 + e.printStackTrace();
  940 + return false;
  941 + }
  942 + }
  943 +
  944 + /**
  945 + * 报警复位命令
  946 + *
  947 + * @param device 视频设备
  948 + */
  949 + @Override
  950 + public boolean alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) {
  951 + try {
  952 + StringBuffer cmdXml = new StringBuffer(200);
  953 + String charset = device.getCharset();
  954 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  955 + cmdXml.append("<Control>\r\n");
  956 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  957 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  958 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  959 + cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
  960 + if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
  961 + cmdXml.append("<Info>\r\n");
  962 + }
  963 + if (!StringUtils.isEmpty(alarmMethod)) {
  964 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  965 + }
  966 + if (!StringUtils.isEmpty(alarmType)) {
  967 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  968 + }
  969 + if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
  970 + cmdXml.append("</Info>\r\n");
  971 + }
  972 + cmdXml.append("</Control>\r\n");
  973 +
  974 + String tm = Long.toString(System.currentTimeMillis());
  975 +
  976 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  977 + : udpSipProvider.getNewCallId();
  978 +
  979 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromAlarm" + tm, null, callIdHeader);
  980 + transmitRequest(device, request, errorEvent);
  981 + return true;
  982 + } catch (SipException | ParseException | InvalidArgumentException e) {
  983 + e.printStackTrace();
  984 + return false;
  985 + }
  986 + }
  987 +
  988 + /**
  989 + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
  990 + *
  991 + * @param device 视频设备
  992 + * @param channelId 预览通道
  993 + */
  994 + @Override
  995 + public boolean iFrameCmd(Device device, String channelId) {
  996 + try {
  997 + StringBuffer cmdXml = new StringBuffer(200);
  998 + String charset = device.getCharset();
  999 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1000 + cmdXml.append("<Control>\r\n");
  1001 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  1002 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1003 + if (StringUtils.isEmpty(channelId)) {
  1004 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1005 + } else {
  1006 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1007 + }
  1008 + cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n");
  1009 + cmdXml.append("</Control>\r\n");
  1010 +
  1011 + String tm = Long.toString(System.currentTimeMillis());
  1012 +
  1013 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1014 + : udpSipProvider.getNewCallId();
  1015 +
  1016 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromBoot" + tm, null, callIdHeader);
  1017 + transmitRequest(device, request);
  1018 + return true;
  1019 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1020 + e.printStackTrace();
  1021 + return false;
  1022 + }
  1023 + }
  1024 +
  1025 + /**
  1026 + * 看守位控制命令
  1027 + *
  1028 + * @param device 视频设备
  1029 + * @param enabled 看守位使能:1 = 开启,0 = 关闭
  1030 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
  1031 + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
  1032 + */
  1033 + @Override
  1034 + public boolean homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) {
  1035 + try {
  1036 + StringBuffer cmdXml = new StringBuffer(200);
  1037 + String charset = device.getCharset();
  1038 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1039 + cmdXml.append("<Control>\r\n");
  1040 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  1041 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1042 + if (StringUtils.isEmpty(channelId)) {
  1043 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1044 + } else {
  1045 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1046 + }
  1047 + cmdXml.append("<HomePosition>\r\n");
  1048 + if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
  1049 + cmdXml.append("<Enabled>1</Enabled>\r\n");
  1050 + if (NumericUtil.isInteger(resetTime)) {
  1051 + cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
  1052 + } else {
  1053 + cmdXml.append("<ResetTime>0</ResetTime>\r\n");
  1054 + }
  1055 + if (NumericUtil.isInteger(presetIndex)) {
  1056 + cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
  1057 + } else {
  1058 + cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
  1059 + }
  1060 + } else {
  1061 + cmdXml.append("<Enabled>0</Enabled>\r\n");
  1062 + }
  1063 + cmdXml.append("</HomePosition>\r\n");
  1064 + cmdXml.append("</Control>\r\n");
  1065 +
  1066 + String tm = Long.toString(System.currentTimeMillis());
  1067 +
  1068 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1069 + : udpSipProvider.getNewCallId();
  1070 +
  1071 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromGuard" + tm, null, callIdHeader);
  1072 + transmitRequest(device, request, errorEvent);
  1073 + return true;
  1074 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1075 + e.printStackTrace();
  1076 + return false;
  1077 + }
  1078 + }
  1079 +
  1080 + /**
  1081 + * 设备配置命令
  1082 + *
  1083 + * @param device 视频设备
  1084 + */
  1085 + @Override
  1086 + public boolean deviceConfigCmd(Device device) {
  1087 + // TODO Auto-generated method stub
  1088 + return false;
  1089 + }
  1090 +
  1091 + /**
  1092 + * 设备配置命令:basicParam
  1093 + *
  1094 + * @param device 视频设备
  1095 + * @param channelId 通道编码(可选)
  1096 + * @param name 设备/通道名称(可选)
  1097 + * @param expiration 注册过期时间(可选)
  1098 + * @param heartBeatInterval 心跳间隔时间(可选)
  1099 + * @param heartBeatCount 心跳超时次数(可选)
  1100 + */
  1101 + @Override
  1102 + public boolean deviceBasicConfigCmd(Device device, String channelId, String name, String expiration,
  1103 + String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) {
  1104 + try {
  1105 + StringBuffer cmdXml = new StringBuffer(200);
  1106 + String charset = device.getCharset();
  1107 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1108 + cmdXml.append("<Control>\r\n");
  1109 + cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
  1110 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1111 + if (StringUtils.isEmpty(channelId)) {
  1112 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1113 + } else {
  1114 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1115 + }
  1116 + cmdXml.append("<BasicParam>\r\n");
  1117 + if (!StringUtils.isEmpty(name)) {
  1118 + cmdXml.append("<Name>" + name + "</Name>\r\n");
  1119 + }
  1120 + if (NumericUtil.isInteger(expiration)) {
  1121 + if (Integer.valueOf(expiration) > 0) {
  1122 + cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n");
  1123 + }
  1124 + }
  1125 + if (NumericUtil.isInteger(heartBeatInterval)) {
  1126 + if (Integer.valueOf(heartBeatInterval) > 0) {
  1127 + cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n");
  1128 + }
  1129 + }
  1130 + if (NumericUtil.isInteger(heartBeatCount)) {
  1131 + if (Integer.valueOf(heartBeatCount) > 0) {
  1132 + cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n");
  1133 + }
  1134 + }
  1135 + cmdXml.append("</BasicParam>\r\n");
  1136 + cmdXml.append("</Control>\r\n");
  1137 +
  1138 + String tm = Long.toString(System.currentTimeMillis());
  1139 +
  1140 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1141 + : udpSipProvider.getNewCallId();
  1142 +
  1143 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromConfig" + tm, null, callIdHeader);
  1144 + transmitRequest(device, request, errorEvent);
  1145 + return true;
  1146 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1147 + e.printStackTrace();
  1148 + return false;
  1149 + }
  1150 + }
  1151 +
  1152 + /**
  1153 + * 查询设备状态
  1154 + *
  1155 + * @param device 视频设备
  1156 + */
  1157 + @Override
  1158 + public boolean deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) {
  1159 + try {
  1160 + String charset = device.getCharset();
  1161 + StringBuffer catalogXml = new StringBuffer(200);
  1162 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1163 + catalogXml.append("<Query>\r\n");
  1164 + catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
  1165 + catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1166 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1167 + catalogXml.append("</Query>\r\n");
  1168 +
  1169 + String tm = Long.toString(System.currentTimeMillis());
  1170 +
  1171 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1172 + : udpSipProvider.getNewCallId();
  1173 +
  1174 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, "FromStatus" + tm, null, callIdHeader);
  1175 +
  1176 + transmitRequest(device, request, errorEvent);
  1177 + return true;
  1178 +
  1179 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1180 + e.printStackTrace();
  1181 + return false;
  1182 + }
  1183 + }
  1184 +
  1185 + /**
  1186 + * 查询设备信息
  1187 + *
  1188 + * @param device 视频设备
  1189 + */
  1190 + @Override
  1191 + public boolean deviceInfoQuery(Device device) {
  1192 + try {
  1193 + StringBuffer catalogXml = new StringBuffer(200);
  1194 + String charset = device.getCharset();
  1195 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1196 + catalogXml.append("<Query>\r\n");
  1197 + catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
  1198 + catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1199 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1200 + catalogXml.append("</Query>\r\n");
  1201 +
  1202 + String tm = Long.toString(System.currentTimeMillis());
  1203 +
  1204 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1205 + : udpSipProvider.getNewCallId();
  1206 +
  1207 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "z9hG4bK-ViaDeviceInfo-" + tm, "FromDev" + tm, null, callIdHeader);
  1208 +
  1209 + transmitRequest(device, request);
  1210 +
  1211 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1212 + e.printStackTrace();
  1213 + return false;
  1214 + }
  1215 + return true;
  1216 + }
  1217 +
  1218 + /**
  1219 + * 查询目录列表
  1220 + *
  1221 + * @param device 视频设备
  1222 + */
  1223 + @Override
  1224 + public boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) {
  1225 + try {
  1226 + StringBuffer catalogXml = new StringBuffer(200);
  1227 + String charset = device.getCharset();
  1228 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1229 + catalogXml.append("<Query>\r\n");
  1230 + catalogXml.append("<CmdType>Catalog</CmdType>\r\n");
  1231 + catalogXml.append("<SN>" + sn + "</SN>\r\n");
  1232 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1233 + catalogXml.append("</Query>\r\n");
  1234 +
  1235 + String tm = Long.toString(System.currentTimeMillis());
  1236 +
  1237 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1238 + : udpSipProvider.getNewCallId();
  1239 +
  1240 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "z9hG4bK-ViaCatalog-" + tm, "FromCat" + tm, null, callIdHeader);
  1241 +
  1242 + transmitRequest(device, request, errorEvent);
  1243 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1244 + e.printStackTrace();
  1245 + return false;
  1246 + }
  1247 + return true;
  1248 + }
  1249 +
  1250 + /**
  1251 + * 查询录像信息
  1252 + *
  1253 + * @param device 视频设备
  1254 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  1255 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  1256 + */
  1257 + @Override
  1258 + public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
  1259 + if (secrecy == null) {
  1260 + secrecy = 0;
  1261 + }
  1262 + if (type == null) {
  1263 + type = "all";
  1264 + }
  1265 + try {
  1266 + StringBuffer recordInfoXml = new StringBuffer(200);
  1267 + String charset = device.getCharset();
  1268 + recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1269 + recordInfoXml.append("<Query>\r\n");
  1270 + recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
  1271 + recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
  1272 + recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1273 + if (startTime != null) {
  1274 + recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
  1275 + }
  1276 + if (endTime != null) {
  1277 + recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
  1278 + }
  1279 + if (secrecy != null) {
  1280 + recordInfoXml.append("<Secrecy> "+ secrecy + " </Secrecy>\r\n");
  1281 + }
  1282 + if (type != null) {
  1283 + // 大华NVR要求必须增加一个值为all的文本元素节点Type
  1284 + recordInfoXml.append("<Type>" + type+"</Type>\r\n");
  1285 + }
  1286 + recordInfoXml.append("</Query>\r\n");
  1287 +
  1288 + String tm = Long.toString(System.currentTimeMillis());
  1289 +
  1290 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1291 + : udpSipProvider.getNewCallId();
  1292 +
  1293 + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
  1294 + "z9hG4bK-ViaRecordInfo-" + tm, "fromRec" + tm, null, callIdHeader);
  1295 +
  1296 + transmitRequest(device, request, errorEvent, okEvent);
  1297 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1298 + e.printStackTrace();
  1299 + return false;
  1300 + }
  1301 + return true;
  1302 + }
  1303 +
  1304 + /**
  1305 + * 查询报警信息
  1306 + *
  1307 + * @param device 视频设备
  1308 + * @param startPriority 报警起始级别(可选)
  1309 + * @param endPriority 报警终止级别(可选)
  1310 + * @param alarmMethod 报警方式条件(可选)
  1311 + * @param alarmType 报警类型
  1312 + * @param startTime 报警发生起始时间(可选)
  1313 + * @param endTime 报警发生终止时间(可选)
  1314 + * @return true = 命令发送成功
  1315 + */
  1316 + @Override
  1317 + public boolean alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType,
  1318 + String startTime, String endTime, SipSubscribe.Event errorEvent) {
  1319 + try {
  1320 + StringBuffer cmdXml = new StringBuffer(200);
  1321 + String charset = device.getCharset();
  1322 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1323 + cmdXml.append("<Query>\r\n");
  1324 + cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
  1325 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1326 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1327 + if (!StringUtils.isEmpty(startPriority)) {
  1328 + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
  1329 + }
  1330 + if (!StringUtils.isEmpty(endPriority)) {
  1331 + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
  1332 + }
  1333 + if (!StringUtils.isEmpty(alarmMethod)) {
  1334 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  1335 + }
  1336 + if (!StringUtils.isEmpty(alarmType)) {
  1337 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  1338 + }
  1339 + if (!StringUtils.isEmpty(startTime)) {
  1340 + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
  1341 + }
  1342 + if (!StringUtils.isEmpty(endTime)) {
  1343 + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
  1344 + }
  1345 + cmdXml.append("</Query>\r\n");
  1346 +
  1347 + String tm = Long.toString(System.currentTimeMillis());
  1348 +
  1349 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1350 + : udpSipProvider.getNewCallId();
  1351 +
  1352 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromAlarm" + tm, null, callIdHeader);
  1353 + transmitRequest(device, request, errorEvent);
  1354 + return true;
  1355 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1356 + e.printStackTrace();
  1357 + return false;
  1358 + }
  1359 + }
  1360 +
  1361 + /**
  1362 + * 查询设备配置
  1363 + *
  1364 + * @param device 视频设备
  1365 + * @param channelId 通道编码(可选)
  1366 + * @param configType 配置类型:
  1367 + */
  1368 + @Override
  1369 + public boolean deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) {
  1370 + try {
  1371 + StringBuffer cmdXml = new StringBuffer(200);
  1372 + String charset = device.getCharset();
  1373 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1374 + cmdXml.append("<Query>\r\n");
  1375 + cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
  1376 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1377 + if (StringUtils.isEmpty(channelId)) {
  1378 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1379 + } else {
  1380 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1381 + }
  1382 + cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n");
  1383 + cmdXml.append("</Query>\r\n");
  1384 +
  1385 + String tm = Long.toString(System.currentTimeMillis());
  1386 +
  1387 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1388 + : udpSipProvider.getNewCallId();
  1389 +
  1390 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromConfig" + tm, null, callIdHeader);
  1391 + transmitRequest(device, request, errorEvent);
  1392 + return true;
  1393 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1394 + e.printStackTrace();
  1395 + return false;
  1396 + }
  1397 + }
  1398 +
  1399 + /**
  1400 + * 查询设备预置位置
  1401 + *
  1402 + * @param device 视频设备
  1403 + */
  1404 + @Override
  1405 + public boolean presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) {
  1406 + try {
  1407 + StringBuffer cmdXml = new StringBuffer(200);
  1408 + String charset = device.getCharset();
  1409 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1410 + cmdXml.append("<Query>\r\n");
  1411 + cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
  1412 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1413 + if (StringUtils.isEmpty(channelId)) {
  1414 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1415 + } else {
  1416 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1417 + }
  1418 + cmdXml.append("</Query>\r\n");
  1419 +
  1420 + String tm = Long.toString(System.currentTimeMillis());
  1421 +
  1422 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1423 + : udpSipProvider.getNewCallId();
  1424 +
  1425 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, "FromConfig" + tm, null, callIdHeader);
  1426 + transmitRequest(device, request, errorEvent);
  1427 + return true;
  1428 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1429 + e.printStackTrace();
  1430 + return false;
  1431 + }
  1432 + }
  1433 +
  1434 + /**
  1435 + * 查询移动设备位置数据
  1436 + *
  1437 + * @param device 视频设备
  1438 + */
  1439 + @Override
  1440 + public boolean mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) {
  1441 + try {
  1442 + StringBuffer mobilePostitionXml = new StringBuffer(200);
  1443 + String charset = device.getCharset();
  1444 + mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1445 + mobilePostitionXml.append("<Query>\r\n");
  1446 + mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
  1447 + mobilePostitionXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1448 + mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1449 + mobilePostitionXml.append("<Interval>60</Interval>\r\n");
  1450 + mobilePostitionXml.append("</Query>\r\n");
  1451 +
  1452 + String tm = Long.toString(System.currentTimeMillis());
  1453 +
  1454 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1455 + : udpSipProvider.getNewCallId();
  1456 +
  1457 + Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, callIdHeader);
  1458 +
  1459 + transmitRequest(device, request, errorEvent);
  1460 +
  1461 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1462 + e.printStackTrace();
  1463 + return false;
  1464 + }
  1465 + return true;
  1466 + }
  1467 +
  1468 + /**
  1469 + * 订阅、取消订阅移动位置
  1470 + *
  1471 + * @param device 视频设备
  1472 + * @return true = 命令发送成功
  1473 + */
  1474 + @Override
  1475 + public boolean mobilePositionSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) {
  1476 + try {
  1477 + StringBuffer subscribePostitionXml = new StringBuffer(200);
  1478 + String charset = device.getCharset();
  1479 + subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1480 + subscribePostitionXml.append("<Query>\r\n");
  1481 + subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
  1482 + subscribePostitionXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1483 + subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1484 + if (device.getSubscribeCycleForMobilePosition() > 0) {
  1485 + subscribePostitionXml.append("<Interval>" + String.valueOf(device.getMobilePositionSubmissionInterval()) + "</Interval>\r\n");
  1486 + }
  1487 + subscribePostitionXml.append("</Query>\r\n");
  1488 +
  1489 + Request request;
  1490 + if (dialog != null) {
  1491 + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  1492 + request = dialog.createRequest(Request.SUBSCRIBE);
  1493 + ExpiresHeader expiresHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForCatalog());
  1494 + request.setExpires(expiresHeader);
  1495 +
  1496 + request.setRequestURI(requestURI);
  1497 +
  1498 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  1499 + request.setContent(subscribePostitionXml.toString(), contentTypeHeader);
  1500 +
  1501 + CSeqHeader cSeqHeader = (CSeqHeader)request.getHeader(CSeqHeader.NAME);
  1502 + cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ(Request.SUBSCRIBE));
  1503 + request.removeHeader(CSeqHeader.NAME);
  1504 + request.addHeader(cSeqHeader);
  1505 + }else {
  1506 + String tm = Long.toString(System.currentTimeMillis());
  1507 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1508 + : udpSipProvider.getNewCallId();
  1509 + request = headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForMobilePosition(), "presence" ,callIdHeader); //Position;id=" + tm.substring(tm.length() - 4));
  1510 + }
  1511 + transmitRequest(device, request, errorEvent, okEvent);
  1512 +
  1513 + return true;
  1514 +
  1515 + } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
  1516 + e.printStackTrace();
  1517 + return false;
  1518 + }
  1519 + }
  1520 +
  1521 + /**
  1522 + * 订阅、取消订阅报警信息
  1523 + *
  1524 + * @param device 视频设备
  1525 + * @param expires 订阅过期时间(0 = 取消订阅)
  1526 + * @param startPriority 报警起始级别(可选)
  1527 + * @param endPriority 报警终止级别(可选)
  1528 + * @param alarmMethod 报警方式条件(可选)
  1529 + * @param alarmType 报警类型
  1530 + * @param startTime 报警发生起始时间(可选)
  1531 + * @param endTime 报警发生终止时间(可选)
  1532 + * @return true = 命令发送成功
  1533 + */
  1534 + @Override
  1535 + public boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) {
  1536 + try {
  1537 + StringBuffer cmdXml = new StringBuffer(200);
  1538 + String charset = device.getCharset();
  1539 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1540 + cmdXml.append("<Query>\r\n");
  1541 + cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
  1542 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1543 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1544 + if (!StringUtils.isEmpty(startPriority)) {
  1545 + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
  1546 + }
  1547 + if (!StringUtils.isEmpty(endPriority)) {
  1548 + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
  1549 + }
  1550 + if (!StringUtils.isEmpty(alarmMethod)) {
  1551 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  1552 + }
  1553 + if (!StringUtils.isEmpty(alarmType)) {
  1554 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  1555 + }
  1556 + if (!StringUtils.isEmpty(startTime)) {
  1557 + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
  1558 + }
  1559 + if (!StringUtils.isEmpty(endTime)) {
  1560 + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
  1561 + }
  1562 + cmdXml.append("</Query>\r\n");
  1563 +
  1564 + String tm = Long.toString(System.currentTimeMillis());
  1565 +
  1566 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1567 + : udpSipProvider.getNewCallId();
  1568 +
  1569 + Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, expires, "presence" , callIdHeader);
  1570 + transmitRequest(device, request);
  1571 +
  1572 + return true;
  1573 +
  1574 + } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
  1575 + e.printStackTrace();
  1576 + return false;
  1577 + }
  1578 + }
  1579 +
  1580 + @Override
  1581 + public boolean catalogSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
  1582 + try {
  1583 + StringBuffer cmdXml = new StringBuffer(200);
  1584 + String charset = device.getCharset();
  1585 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1586 + cmdXml.append("<Query>\r\n");
  1587 + cmdXml.append("<CmdType>Catalog</CmdType>\r\n");
  1588 + cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1589 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1590 + cmdXml.append("</Query>\r\n");
  1591 +
  1592 +
  1593 + Request request;
  1594 + if (dialog != null) {
  1595 + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  1596 + request = dialog.createRequest(Request.SUBSCRIBE);
  1597 + ExpiresHeader expiresHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForCatalog());
  1598 + request.setExpires(expiresHeader);
  1599 +
  1600 + request.setRequestURI(requestURI);
  1601 +
  1602 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  1603 + request.setContent(cmdXml.toString(), contentTypeHeader);
  1604 +
  1605 + CSeqHeader cSeqHeader = (CSeqHeader)request.getHeader(CSeqHeader.NAME);
  1606 + cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ(Request.SUBSCRIBE));
  1607 + request.removeHeader(CSeqHeader.NAME);
  1608 + request.addHeader(cSeqHeader);
  1609 +
  1610 + }else {
  1611 + String tm = Long.toString(System.currentTimeMillis());
  1612 +
  1613 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1614 + : udpSipProvider.getNewCallId();
  1615 +
  1616 + // 有效时间默认为60秒以上
  1617 + request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
  1618 + "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,
  1619 + callIdHeader);
  1620 +
  1621 + }
  1622 + transmitRequest(device, request, errorEvent, okEvent);
  1623 + return true;
  1624 +
  1625 + } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
  1626 + e.printStackTrace();
  1627 + return false;
  1628 + }
  1629 + }
  1630 +
  1631 + @Override
  1632 + public boolean dragZoomCmd(Device device, String channelId, String cmdString) {
  1633 + try {
  1634 + StringBuffer dragXml = new StringBuffer(200);
  1635 + String charset = device.getCharset();
  1636 + dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1637 + dragXml.append("<Control>\r\n");
  1638 + dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  1639 + dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1640 + if (StringUtils.isEmpty(channelId)) {
  1641 + dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1642 + } else {
  1643 + dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1644 + }
  1645 + dragXml.append(cmdString);
  1646 + dragXml.append("</Control>\r\n");
  1647 + String tm = Long.toString(System.currentTimeMillis());
  1648 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1649 + : udpSipProvider.getNewCallId();
  1650 + Request request = headerProvider.createMessageRequest(device, dragXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
  1651 + logger.debug("拉框信令: " + request.toString());
  1652 + transmitRequest(device, request);
  1653 + return true;
  1654 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1655 + e.printStackTrace();
  1656 + }
  1657 + return false;
  1658 + }
  1659 +
  1660 +
  1661 + private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
  1662 + return transmitRequest(device, request, null, null);
  1663 + }
  1664 +
  1665 + private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent) throws SipException {
  1666 + return transmitRequest(device, request, errorEvent, null);
  1667 + }
  1668 +
  1669 + private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException {
  1670 + ClientTransaction clientTransaction = null;
  1671 + if("TCP".equals(device.getTransport())) {
  1672 + clientTransaction = tcpSipProvider.getNewClientTransaction(request);
  1673 + } else if("UDP".equals(device.getTransport())) {
  1674 + clientTransaction = udpSipProvider.getNewClientTransaction(request);
  1675 + }
  1676 + if (request.getHeader(UserAgentHeader.NAME) == null) {
  1677 + List<String> agentParam = new ArrayList<>();
  1678 + agentParam.add("wvp-pro");
  1679 + // TODO 添加版本信息以及日期
  1680 + UserAgentHeader userAgentHeader = null;
  1681 + try {
  1682 + userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
  1683 + } catch (ParseException e) {
  1684 + throw new RuntimeException(e);
  1685 + }
  1686 + request.addHeader(userAgentHeader);
  1687 + }
  1688 + CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
  1689 + // 添加错误订阅
  1690 + if (errorEvent != null) {
  1691 + sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
  1692 + errorEvent.response(eventResult);
  1693 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  1694 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  1695 + }));
  1696 + }
  1697 + // 添加订阅
  1698 + if (okEvent != null) {
  1699 + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult ->{
  1700 + okEvent.response(eventResult);
  1701 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  1702 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  1703 + });
  1704 + }
  1705 +
  1706 + clientTransaction.sendRequest();
  1707 + return clientTransaction;
  1708 + }
  1709 +
  1710 + /**
  1711 + * 回放暂停
  1712 + */
  1713 + @Override
  1714 + public void playPauseCmd(Device device, StreamInfo streamInfo) {
  1715 + try {
  1716 + Long cseq = redisCatchStorage.getCSEQ(Request.INFO);
  1717 + StringBuffer content = new StringBuffer(200);
  1718 + content.append("PAUSE RTSP/1.0\r\n");
  1719 + content.append("CSeq: " + cseq + "\r\n");
  1720 + content.append("PauseTime: now\r\n");
  1721 + Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
  1722 + if (request == null) {
  1723 + return;
  1724 + }
  1725 + logger.info(request.toString());
  1726 + ClientTransaction clientTransaction = null;
  1727 + if ("TCP".equals(device.getTransport())) {
  1728 + clientTransaction = tcpSipProvider.getNewClientTransaction(request);
  1729 + } else if ("UDP".equals(device.getTransport())) {
  1730 + clientTransaction = udpSipProvider.getNewClientTransaction(request);
  1731 + }
  1732 + if (clientTransaction != null) {
  1733 + clientTransaction.sendRequest();
  1734 + }
  1735 +
  1736 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1737 + e.printStackTrace();
  1738 + }
  1739 + }
  1740 +
  1741 + /**
  1742 + * 回放恢复
  1743 + */
  1744 + @Override
  1745 + public void playResumeCmd(Device device, StreamInfo streamInfo) {
  1746 + try {
  1747 + Long cseq = redisCatchStorage.getCSEQ(Request.INFO);
  1748 + StringBuffer content = new StringBuffer(200);
  1749 + content.append("PLAY RTSP/1.0\r\n");
  1750 + content.append("CSeq: " + cseq + "\r\n");
  1751 + content.append("Range: npt=now-\r\n");
  1752 + Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
  1753 + if (request == null) {
  1754 + return;
  1755 + }
  1756 + logger.info(request.toString());
  1757 + ClientTransaction clientTransaction = null;
  1758 + if ("TCP".equals(device.getTransport())) {
  1759 + clientTransaction = tcpSipProvider.getNewClientTransaction(request);
  1760 + } else if ("UDP".equals(device.getTransport())) {
  1761 + clientTransaction = udpSipProvider.getNewClientTransaction(request);
  1762 + }
  1763 +
  1764 + clientTransaction.sendRequest();
  1765 +
  1766 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1767 + e.printStackTrace();
  1768 + }
  1769 + }
  1770 +
  1771 + /**
  1772 + * 回放拖动播放
  1773 + */
  1774 + @Override
  1775 + public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) {
  1776 + try {
  1777 + Long cseq = redisCatchStorage.getCSEQ(Request.INFO);
  1778 + StringBuffer content = new StringBuffer(200);
  1779 + content.append("PLAY RTSP/1.0\r\n");
  1780 + content.append("CSeq: " + cseq + "\r\n");
  1781 + content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");
  1782 +
  1783 + Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
  1784 + if (request == null) {
  1785 + return;
  1786 + }
  1787 + logger.info(request.toString());
  1788 + ClientTransaction clientTransaction = null;
  1789 + if ("TCP".equals(device.getTransport())) {
  1790 + clientTransaction = tcpSipProvider.getNewClientTransaction(request);
  1791 + } else if ("UDP".equals(device.getTransport())) {
  1792 + clientTransaction = udpSipProvider.getNewClientTransaction(request);
  1793 + }
  1794 +
  1795 + clientTransaction.sendRequest();
  1796 +
  1797 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1798 + e.printStackTrace();
  1799 + }
  1800 + }
  1801 +
  1802 + /**
  1803 + * 回放倍速播放
  1804 + */
  1805 + @Override
  1806 + public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) {
  1807 + try {
  1808 + Long cseq = redisCatchStorage.getCSEQ(Request.INFO);
  1809 + StringBuffer content = new StringBuffer(200);
  1810 + content.append("PLAY RTSP/1.0\r\n");
  1811 + content.append("CSeq: " + cseq + "\r\n");
  1812 + content.append("Scale: " + String.format("%.1f",speed) + "\r\n");
  1813 + Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
  1814 + if (request == null) {
  1815 + return;
  1816 + }
  1817 + logger.info(request.toString());
  1818 + ClientTransaction clientTransaction = null;
  1819 + if ("TCP".equals(device.getTransport())) {
  1820 + clientTransaction = tcpSipProvider.getNewClientTransaction(request);
  1821 + } else if ("UDP".equals(device.getTransport())) {
  1822 + clientTransaction = udpSipProvider.getNewClientTransaction(request);
  1823 + }
  1824 +
  1825 + clientTransaction.sendRequest();
  1826 +
  1827 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1828 + e.printStackTrace();
  1829 + }
  1830 + }
  1831 +
  1832 + @Override
  1833 + public void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) {
  1834 + try {
  1835 + Request request = headerProvider.createInfoRequest(device, streamInfo, content);
  1836 + if (request == null) {
  1837 + return;
  1838 + }
  1839 + logger.info(request.toString());
  1840 + ClientTransaction clientTransaction = null;
  1841 + if ("TCP".equals(device.getTransport())) {
  1842 + clientTransaction = tcpSipProvider.getNewClientTransaction(request);
  1843 + } else if ("UDP".equals(device.getTransport())) {
  1844 + clientTransaction = udpSipProvider.getNewClientTransaction(request);
  1845 + }
  1846 + CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
  1847 + if(errorEvent != null) {
  1848 + sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
  1849 + errorEvent.response(eventResult);
  1850 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  1851 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  1852 + }));
  1853 + }
  1854 +
  1855 + if(okEvent != null) {
  1856 + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
  1857 + okEvent.response(eventResult);
  1858 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  1859 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  1860 + });
  1861 + }
  1862 + clientTransaction.sendRequest();
  1863 +
  1864 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1865 + e.printStackTrace();
  1866 + }
  1867 + }
  1868 +
  1869 + @Override
  1870 + public boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) {
  1871 + if (device == null) {
  1872 + return false;
  1873 + }
  1874 + logger.info("[发送 报警通知] {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(),
  1875 + deviceAlarm.getLongitude(), deviceAlarm.getLatitude());
  1876 + try {
  1877 + String characterSet = device.getCharset();
  1878 + StringBuffer deviceStatusXml = new StringBuffer(600);
  1879 + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
  1880 + deviceStatusXml.append("<Notify>\r\n");
  1881 + deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n");
  1882 + deviceStatusXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  1883 + deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n");
  1884 + deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n");
  1885 + deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n");
  1886 + deviceStatusXml.append("<AlarmTime>" + deviceAlarm.getAlarmTime() + "</AlarmTime>\r\n");
  1887 + deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n");
  1888 + deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n");
  1889 + deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n");
  1890 + deviceStatusXml.append("<info>\r\n");
  1891 + deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n");
  1892 + deviceStatusXml.append("</info>\r\n");
  1893 + deviceStatusXml.append("</Notify>\r\n");
  1894 +
  1895 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1896 + : udpSipProvider.getNewCallId();
  1897 + String tm = Long.toString(System.currentTimeMillis());
  1898 + Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null, callIdHeader);
  1899 + transmitRequest(device, request);
  1900 +
  1901 +
  1902 + } catch (SipException | ParseException e) {
  1903 + e.printStackTrace();
  1904 + return false;
  1905 + } catch (InvalidArgumentException e) {
  1906 + throw new RuntimeException(e);
  1907 + }
  1908 + return true;
  1909 + }
  1910 +
  1911 + private void sendNotify(Device device, String catalogXmlContent,
  1912 + SubscribeInfo subscribeInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent )
  1913 + throws NoSuchFieldException, IllegalAccessException, SipException, ParseException {
  1914 + MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory();
  1915 + String characterSet = device.getCharset();
  1916 + // 设置编码, 防止中文乱码
  1917 + messageFactory.setDefaultContentEncodingCharset(characterSet);
  1918 + Dialog dialog = subscribeInfo.getDialog();
  1919 + if (dialog == null || !dialog.getState().equals(DialogState.CONFIRMED)) {
  1920 + return;
  1921 + }
  1922 + SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY);
  1923 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  1924 + notifyRequest.setContent(catalogXmlContent, contentTypeHeader);
  1925 +
  1926 + SubscriptionStateHeader subscriptionState = sipFactory.createHeaderFactory()
  1927 + .createSubscriptionStateHeader(SubscriptionStateHeader.ACTIVE);
  1928 + notifyRequest.addHeader(subscriptionState);
  1929 +
  1930 + EventHeader event = sipFactory.createHeaderFactory().createEventHeader(subscribeInfo.getEventType());
  1931 + if (subscribeInfo.getEventId() != null) {
  1932 + event.setEventId(subscribeInfo.getEventId());
  1933 + }
  1934 + notifyRequest.addHeader(event);
  1935 +
  1936 + SipURI sipURI = (SipURI) notifyRequest.getRequestURI();
  1937 + if (subscribeInfo.getTransaction() != null) {
  1938 + SIPRequest request = (SIPRequest) subscribeInfo.getTransaction().getRequest();
  1939 + sipURI.setHost(request.getRemoteAddress().getHostAddress());
  1940 + sipURI.setPort(request.getRemotePort());
  1941 + }else {
  1942 + sipURI.setHost(device.getIp());
  1943 + sipURI.setPort(device.getPort());
  1944 + }
  1945 +
  1946 + ClientTransaction transaction = null;
  1947 + if ("TCP".equals(device.getTransport())) {
  1948 + transaction = tcpSipProvider.getNewClientTransaction(notifyRequest);
  1949 + } else if ("UDP".equals(device.getTransport())) {
  1950 + transaction = udpSipProvider.getNewClientTransaction(notifyRequest);
  1951 + }
  1952 + // 添加错误订阅
  1953 + if (errorEvent != null) {
  1954 + sipSubscribe.addErrorSubscribe(subscribeInfo.getCallId(), errorEvent);
  1955 + }
  1956 + // 添加订阅
  1957 + if (okEvent != null) {
  1958 + sipSubscribe.addOkSubscribe(subscribeInfo.getCallId(), okEvent);
  1959 + }
  1960 + if (transaction == null) {
  1961 + logger.error("平台{}的Transport错误:{}",device.getDeviceId(), device.getTransport());
  1962 + return;
  1963 + }
  1964 + dialog.sendRequest(transaction);
  1965 +
  1966 + }
  1967 +}
... ...
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;
2   -
3   -import com.genersoft.iot.vmp.common.StreamInfo;
4   -import com.genersoft.iot.vmp.gb28181.bean.*;
5   -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6   -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
7   -import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
8   -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.SIPRequestProcessorParent;
11   -import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
12   -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13   -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
14   -import gov.nist.javax.sip.message.SIPRequest;
15   -import org.slf4j.Logger;
16   -import org.slf4j.LoggerFactory;
17   -import org.springframework.beans.factory.InitializingBean;
18   -import org.springframework.beans.factory.annotation.Autowired;
19   -import org.springframework.stereotype.Component;
20   -import javax.sip.InvalidArgumentException;
21   -import javax.sip.RequestEvent;
22   -import javax.sip.SipException;
23   -import javax.sip.header.*;
24   -import javax.sip.message.Response;
25   -import java.text.ParseException;
26   -
27   -@Component
28   -public class InfoRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
29   -
30   - private final static Logger logger = LoggerFactory.getLogger(InfoRequestProcessor.class);
31   -
32   - private final String method = "INFO";
33   -
34   - @Autowired
35   - private SIPProcessorObserver sipProcessorObserver;
36   -
37   - @Autowired
38   - private IVideoManagerStorage storage;
39   -
40   - @Autowired
41   - private SipSubscribe sipSubscribe;
42   -
43   - @Autowired
44   - private IRedisCatchStorage redisCatchStorage;
45   -
46   - @Autowired
47   - private IVideoManagerStorage storager;
48   -
49   - @Autowired
50   - private SIPCommander cmder;
51   -
52   - @Autowired
53   - private VideoStreamSessionManager sessionManager;
54   -
55   - @Override
56   - public void afterPropertiesSet() throws Exception {
57   - // 添加消息处理的订阅
58   - sipProcessorObserver.addRequestProcessor(method, this);
59   - }
60   -
61   - @Override
62   - public void process(RequestEvent evt) {
63   - logger.debug("接收到消息:" + evt.getRequest());
64   - String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
65   - CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
66   - // 先从会话内查找
67   - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
68   - if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题
69   - deviceId = ssrcTransaction.getDeviceId();
70   - }
71   - // 查询设备是否存在
72   - Device device = redisCatchStorage.getDevice(deviceId);
73   - // 查询上级平台是否存在
74   - ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId);
75   - try {
76   - if (device != null && parentPlatform != null) {
77   - logger.warn("[重复]平台与设备编号重复:{}", deviceId);
78   - SIPRequest request = (SIPRequest) evt.getRequest();
79   - String hostAddress = request.getRemoteAddress().getHostAddress();
80   - int remotePort = request.getRemotePort();
81   - if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) {
82   - parentPlatform = null;
83   - }else {
84   - device = null;
85   - }
86   - }
87   - if (device == null && parentPlatform == null) {
88   - // 不存在则回复404
89   - responseAck(evt, Response.NOT_FOUND, "device "+ deviceId +" not found");
90   - logger.warn("[设备未找到 ]: {}", deviceId);
91   - if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){
92   - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new DeviceNotFoundEvent(evt.getDialog()));
93   - sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
94   - };
95   - }else {
96   - ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME);
97   - String contentType = header.getContentType();
98   - String contentSubType = header.getContentSubType();
99   - if ("Application".equals(contentType) && "MANSRTSP".equals(contentSubType)) {
100   - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
101   - String streamId = sendRtpItem.getStreamId();
102   - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
103   - if (null == streamInfo) {
104   - responseAck(evt, Response.NOT_FOUND, "stream " + streamId + " not found");
105   - return;
106   - }
107   - Device device1 = storager.queryVideoDevice(streamInfo.getDeviceID());
108   - cmder.playbackControlCmd(device1,streamInfo,new String(evt.getRequest().getRawContent()),eventResult -> {
109   - // 失败的回复
110   - try {
111   - responseAck(evt, eventResult.statusCode, eventResult.msg);
112   - } catch (SipException e) {
113   - e.printStackTrace();
114   - } catch (InvalidArgumentException e) {
115   - e.printStackTrace();
116   - } catch (ParseException e) {
117   - e.printStackTrace();
118   - }
119   - }, eventResult -> {
120   - // 成功的回复
121   - try {
122   - responseAck(evt, eventResult.statusCode);
123   - } catch (SipException e) {
124   - e.printStackTrace();
125   - } catch (InvalidArgumentException e) {
126   - e.printStackTrace();
127   - } catch (ParseException e) {
128   - e.printStackTrace();
129   - }
130   - });
131   - }
132   - }
133   - } catch (SipException e) {
134   - logger.warn("SIP 回复错误", e);
135   - } catch (InvalidArgumentException e) {
136   - logger.warn("参数无效", e);
137   - } catch (ParseException e) {
138   - logger.warn("SIP回复时解析异常", e);
139   - }
140   - }
141   -
142   -
143   -}
  1 +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info;
  2 +
  3 +import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.gb28181.bean.*;
  5 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  6 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  7 +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
  8 +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.SIPRequestProcessorParent;
  11 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  12 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  13 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  14 +import gov.nist.javax.sip.message.SIPRequest;
  15 +import org.slf4j.Logger;
  16 +import org.slf4j.LoggerFactory;
  17 +import org.springframework.beans.factory.InitializingBean;
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.stereotype.Component;
  20 +import javax.sip.InvalidArgumentException;
  21 +import javax.sip.RequestEvent;
  22 +import javax.sip.SipException;
  23 +import javax.sip.header.*;
  24 +import javax.sip.message.Response;
  25 +import java.text.ParseException;
  26 +
  27 +@Component
  28 +public class InfoRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
  29 +
  30 + private final static Logger logger = LoggerFactory.getLogger(InfoRequestProcessor.class);
  31 +
  32 + private final String method = "INFO";
  33 +
  34 + @Autowired
  35 + private SIPProcessorObserver sipProcessorObserver;
  36 +
  37 + @Autowired
  38 + private IVideoManagerStorage storage;
  39 +
  40 + @Autowired
  41 + private SipSubscribe sipSubscribe;
  42 +
  43 + @Autowired
  44 + private IRedisCatchStorage redisCatchStorage;
  45 +
  46 + @Autowired
  47 + private IVideoManagerStorage storager;
  48 +
  49 + @Autowired
  50 + private SIPCommander cmder;
  51 +
  52 + @Autowired
  53 + private VideoStreamSessionManager sessionManager;
  54 +
  55 + @Override
  56 + public void afterPropertiesSet() throws Exception {
  57 + // 添加消息处理的订阅
  58 + sipProcessorObserver.addRequestProcessor(method, this);
  59 + }
  60 +
  61 + @Override
  62 + public void process(RequestEvent evt) {
  63 + logger.debug("接收到消息:" + evt.getRequest());
  64 + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
  65 + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
  66 + // 先从会话内查找
  67 + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
  68 + if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题
  69 + deviceId = ssrcTransaction.getDeviceId();
  70 + }
  71 + // 查询设备是否存在
  72 + Device device = redisCatchStorage.getDevice(deviceId);
  73 + // 查询上级平台是否存在
  74 + ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId);
  75 + try {
  76 + if (device != null && parentPlatform != null) {
  77 + logger.warn("[重复]平台与设备编号重复:{}", deviceId);
  78 + SIPRequest request = (SIPRequest) evt.getRequest();
  79 + String hostAddress = request.getRemoteAddress().getHostAddress();
  80 + int remotePort = request.getRemotePort();
  81 + if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) {
  82 + parentPlatform = null;
  83 + }else {
  84 + device = null;
  85 + }
  86 + }
  87 + if (device == null && parentPlatform == null) {
  88 + // 不存在则回复404
  89 + responseAck(evt, Response.NOT_FOUND, "device "+ deviceId +" not found");
  90 + logger.warn("[设备未找到 ]: {}", deviceId);
  91 + if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){
  92 + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new DeviceNotFoundEvent(evt.getDialog()));
  93 + sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
  94 + };
  95 + }else {
  96 + ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME);
  97 + String contentType = header.getContentType();
  98 + String contentSubType = header.getContentSubType();
  99 + if ("Application".equals(contentType) && "MANSRTSP".equals(contentSubType)) {
  100 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
  101 + String streamId = sendRtpItem.getStreamId();
  102 + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
  103 + if (null == streamInfo) {
  104 + responseAck(evt, Response.NOT_FOUND, "stream " + streamId + " not found");
  105 + return;
  106 + }
  107 + Device device1 = storager.queryVideoDevice(streamInfo.getDeviceID());
  108 + cmder.playbackControlCmd(device1,streamInfo,new String(evt.getRequest().getRawContent()),eventResult -> {
  109 + // 失败的回复
  110 + try {
  111 + responseAck(evt, eventResult.statusCode, eventResult.msg);
  112 + } catch (SipException e) {
  113 + e.printStackTrace();
  114 + } catch (InvalidArgumentException e) {
  115 + e.printStackTrace();
  116 + } catch (ParseException e) {
  117 + e.printStackTrace();
  118 + }
  119 + }, eventResult -> {
  120 + // 成功的回复
  121 + try {
  122 + responseAck(evt, eventResult.statusCode);
  123 + } catch (SipException e) {
  124 + e.printStackTrace();
  125 + } catch (InvalidArgumentException e) {
  126 + e.printStackTrace();
  127 + } catch (ParseException e) {
  128 + e.printStackTrace();
  129 + }
  130 + });
  131 + }
  132 + }
  133 + } catch (SipException e) {
  134 + logger.warn("SIP 回复错误", e);
  135 + } catch (InvalidArgumentException e) {
  136 + logger.warn("参数无效", e);
  137 + } catch (ParseException e) {
  138 + logger.warn("SIP回复时解析异常", e);
  139 + }
  140 + }
  141 +
  142 +
  143 +}
... ...