Commit 2a273acd09cc5e9656a5cf2673c98d7b5e8453df
1 parent
3609d361
增加上级平台云台控制功能
Showing
4 changed files
with
90 additions
and
34 deletions
README.md
| ... | ... | @@ -60,21 +60,24 @@ https://gitee.com/18010473990/wvp-GB28181.git |
| 60 | 60 | 15. 支持订阅与通知方法 |
| 61 | 61 | - [X] 移动位置订阅 |
| 62 | 62 | - [X] 移动位置通知处理 |
| 63 | - - [ ] 报警事件订阅 | |
| 63 | + - [X] 报警事件订阅 | |
| 64 | 64 | - [X] 报警事件通知处理 |
| 65 | 65 | - [ ] 设备目录订阅 |
| 66 | 66 | - [X] 设备目录通知处理 |
| 67 | 67 | 16. 移动位置查询和显示,可通过配置文件设置移动位置历史是否存储 |
| 68 | 68 | |
| 69 | 69 | # 2.0 支持特性 |
| 70 | -- [ ] 国标通道向上级联 | |
| 70 | +- [X] 国标通道向上级联 | |
| 71 | 71 | - [X] WEB添加上级平台 |
| 72 | 72 | - [X] 注册 |
| 73 | 73 | - [X] 心跳保活 |
| 74 | 74 | - [X] 通道选择 |
| 75 | 75 | - [X] 通道推送 |
| 76 | - - [ ] 点播 | |
| 77 | - - [ ] 云台控制 | |
| 76 | + - [X] 点播 | |
| 77 | + - [X] 云台控制 | |
| 78 | + - [X] 平台状态查询 | |
| 79 | + - [X] 平台信息查询 | |
| 80 | + - [X] 平台远程启动 | |
| 78 | 81 | - [ ] 添加RTSP视频 |
| 79 | 82 | - [ ] 添加ONVIF探测局域网内的设备 |
| 80 | 83 | - [ ] 添加RTMP视频 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
| ... | ... | @@ -78,6 +78,14 @@ public interface ISIPCommander { |
| 78 | 78 | boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2); |
| 79 | 79 | |
| 80 | 80 | /** |
| 81 | + * 前端控制指令(用于转发上级指令) | |
| 82 | + * @param device 控制设备 | |
| 83 | + * @param channelId 预览通道 | |
| 84 | + * @param cmdString 前端控制指令串 | |
| 85 | + */ | |
| 86 | + boolean fronEndCmd(Device device, String channelId, String cmdString); | |
| 87 | + | |
| 88 | + /** | |
| 81 | 89 | * 请求预览视频流 |
| 82 | 90 | * |
| 83 | 91 | * @param device 视频设备 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -282,6 +282,36 @@ public class SIPCommander implements ISIPCommander { |
| 282 | 282 | } |
| 283 | 283 | |
| 284 | 284 | /** |
| 285 | + * 前端控制指令(用于转发上级指令) | |
| 286 | + * @param device 控制设备 | |
| 287 | + * @param channelId 预览通道 | |
| 288 | + * @param cmdString 前端控制指令串 | |
| 289 | + */ | |
| 290 | + @Override | |
| 291 | + public boolean fronEndCmd(Device device, String channelId, String cmdString) { | |
| 292 | + try { | |
| 293 | + StringBuffer ptzXml = new StringBuffer(200); | |
| 294 | + ptzXml.append("<?xml version=\"1.0\" ?>\r\n"); | |
| 295 | + ptzXml.append("<Control>\r\n"); | |
| 296 | + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n"); | |
| 297 | + ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); | |
| 298 | + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n"); | |
| 299 | + ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n"); | |
| 300 | + ptzXml.append("<Info>\r\n"); | |
| 301 | + ptzXml.append("</Info>\r\n"); | |
| 302 | + ptzXml.append("</Control>\r\n"); | |
| 303 | + | |
| 304 | + String tm = Long.toString(System.currentTimeMillis()); | |
| 305 | + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null); | |
| 306 | + transmitRequest(device, request); | |
| 307 | + return true; | |
| 308 | + } catch (SipException | ParseException | InvalidArgumentException e) { | |
| 309 | + e.printStackTrace(); | |
| 310 | + } | |
| 311 | + return false; | |
| 312 | + } | |
| 313 | + | |
| 314 | + /** | |
| 285 | 315 | * 请求预览视频流 |
| 286 | 316 | * @param device 视频设备 |
| 287 | 317 | * @param channelId 预览通道 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
| ... | ... | @@ -4,8 +4,11 @@ import java.io.ByteArrayInputStream; |
| 4 | 4 | import java.text.ParseException; |
| 5 | 5 | import java.util.*; |
| 6 | 6 | |
| 7 | +import javax.sip.address.SipURI; | |
| 8 | + | |
| 7 | 9 | import javax.sip.header.FromHeader; |
| 8 | 10 | import javax.sip.header.HeaderAddress; |
| 11 | +import javax.sip.header.ToHeader; | |
| 9 | 12 | import javax.sip.InvalidArgumentException; |
| 10 | 13 | import javax.sip.ListeningPoint; |
| 11 | 14 | import javax.sip.ObjectInUseException; |
| ... | ... | @@ -290,38 +293,50 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 290 | 293 | deferredResultHolder.invokeResult(msg); |
| 291 | 294 | } else { |
| 292 | 295 | // 此处是上级发出的DeviceControl指令 |
| 293 | - if (XmlUtil.getText(rootElement, "TeleBoot").equals("Boot") ) { // 远程启动功能:需要在重新启动程序后先对SipStack解绑 | |
| 294 | - String platformId = ((SipUri) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); | |
| 295 | - logger.info("执行远程启动命令"); | |
| 296 | - ParentPlatform parentPlatform = storager.queryParentPlatById(platformId); | |
| 297 | - cmderFroPlatform.unregister(parentPlatform, null, null); | |
| 298 | - | |
| 299 | - Thread restartThread = new Thread(new Runnable() { | |
| 300 | - @Override | |
| 301 | - public void run() { | |
| 302 | - try { | |
| 303 | - Thread.sleep(3000); | |
| 304 | - SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); | |
| 305 | - SipStackImpl stack = (SipStackImpl)up.getSipStack(); | |
| 306 | - stack.stop(); | |
| 307 | - Iterator listener = stack.getListeningPoints(); | |
| 308 | - while (listener.hasNext()) { | |
| 309 | - stack.deleteListeningPoint((ListeningPoint) listener.next()); | |
| 310 | - } | |
| 311 | - Iterator providers = stack.getSipProviders(); | |
| 312 | - while (providers.hasNext()) { | |
| 313 | - stack.deleteSipProvider((SipProvider) providers.next()); | |
| 296 | + String platformId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser(); | |
| 297 | + String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); | |
| 298 | + // 远程启动功能 | |
| 299 | + if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) { | |
| 300 | + if (deviceId.equals(targetGBId)) { | |
| 301 | + // 远程启动功能:需要在重新启动程序后先对SipStack解绑 | |
| 302 | + logger.info("执行远程启动本平台命令"); | |
| 303 | + ParentPlatform parentPlatform = storager.queryParentPlatById(platformId); | |
| 304 | + cmderFroPlatform.unregister(parentPlatform, null, null); | |
| 305 | + | |
| 306 | + Thread restartThread = new Thread(new Runnable() { | |
| 307 | + @Override | |
| 308 | + public void run() { | |
| 309 | + try { | |
| 310 | + Thread.sleep(3000); | |
| 311 | + SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider"); | |
| 312 | + SipStackImpl stack = (SipStackImpl)up.getSipStack(); | |
| 313 | + stack.stop(); | |
| 314 | + Iterator listener = stack.getListeningPoints(); | |
| 315 | + while (listener.hasNext()) { | |
| 316 | + stack.deleteListeningPoint((ListeningPoint) listener.next()); | |
| 317 | + } | |
| 318 | + Iterator providers = stack.getSipProviders(); | |
| 319 | + while (providers.hasNext()) { | |
| 320 | + stack.deleteSipProvider((SipProvider) providers.next()); | |
| 321 | + } | |
| 322 | + VManageBootstrap.restart(); | |
| 323 | + } catch (InterruptedException ignored) { | |
| 324 | + } catch (ObjectInUseException e) { | |
| 325 | + e.printStackTrace(); | |
| 314 | 326 | } |
| 315 | - VManageBootstrap.restart(); | |
| 316 | - } catch (InterruptedException ignored) { | |
| 317 | - } catch (ObjectInUseException e) { | |
| 318 | - e.printStackTrace(); | |
| 319 | 327 | } |
| 320 | - } | |
| 321 | - }); | |
| 322 | - | |
| 323 | - restartThread.setDaemon(false); | |
| 324 | - restartThread.start(); | |
| 328 | + }); | |
| 329 | + | |
| 330 | + restartThread.setDaemon(false); | |
| 331 | + restartThread.start(); | |
| 332 | + } else { | |
| 333 | + // 远程启动指定设备 | |
| 334 | + } | |
| 335 | + } | |
| 336 | + if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) { | |
| 337 | + String cmdString = XmlUtil.getText(rootElement,"PTZCmd"); | |
| 338 | + Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, deviceId); | |
| 339 | + cmder.fronEndCmd(device, deviceId, cmdString); | |
| 325 | 340 | } |
| 326 | 341 | } |
| 327 | 342 | } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { | ... | ... |