Commit c2aaae9325db012c9960b69784330ced5ec15ab9

Authored by 648540858
1 parent 9f0ef439

初步实现语音喊话

Showing 20 changed files with 761 additions and 179 deletions
src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +
  4 +/**
  5 + * 缓存语音广播的状态
  6 + * @author lin
  7 + */
  8 +public class AudioBroadcastCatch {
  9 +
  10 +
  11 + public AudioBroadcastCatch(String deviceId, String channelId, AudioBroadcastCatchStatus status) {
  12 + this.deviceId = deviceId;
  13 + this.channelId = channelId;
  14 + this.status = status;
  15 + }
  16 +
  17 + public AudioBroadcastCatch() {
  18 + }
  19 +
  20 + /**
  21 + * 设备编号
  22 + */
  23 + private String deviceId;
  24 +
  25 + /**
  26 + * 通道编号
  27 + */
  28 + private String channelId;
  29 +
  30 + /**
  31 + * 语音广播状态
  32 + */
  33 + private AudioBroadcastCatchStatus status;
  34 +
  35 +
  36 + public String getDeviceId() {
  37 + return deviceId;
  38 + }
  39 +
  40 + public void setDeviceId(String deviceId) {
  41 + this.deviceId = deviceId;
  42 + }
  43 +
  44 + public String getChannelId() {
  45 + return channelId;
  46 + }
  47 +
  48 + public void setChannelId(String channelId) {
  49 + this.channelId = channelId;
  50 + }
  51 +
  52 + public AudioBroadcastCatchStatus getStatus() {
  53 + return status;
  54 + }
  55 +
  56 + public void setStatus(AudioBroadcastCatchStatus status) {
  57 + this.status = status;
  58 + }
  59 +}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatchStatus.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +/**
  4 + * 语音广播状态
  5 + * @author lin
  6 + */
  7 +public enum AudioBroadcastCatchStatus {
  8 +
  9 + // 发送语音广播消息等待对方回复语音广播
  10 + Ready,
  11 + // 收到回复等待invite消息
  12 + WaiteInvite,
  13 + // 收到invite消息
  14 + Ok,
  15 +}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -134,16 +134,6 @@ public class Device { @@ -134,16 +134,6 @@ public class Device {
134 */ 134 */
135 private boolean ssrcCheck; 135 private boolean ssrcCheck;
136 136
137 - /**  
138 - * 设备用于接收语音消息的通道  
139 - */  
140 - private String audioChannelForReceive;  
141 -  
142 - /**  
143 - * 设备用于发送语音消息的通道  
144 - */  
145 - private String audioChannelForSend;  
146 -  
147 137
148 public String getDeviceId() { 138 public String getDeviceId() {
149 return deviceId; 139 return deviceId;
@@ -345,11 +335,4 @@ public class Device { @@ -345,11 +335,4 @@ public class Device {
345 this.ssrcCheck = ssrcCheck; 335 this.ssrcCheck = ssrcCheck;
346 } 336 }
347 337
348 - public String getAudioChannelForReceive() {  
349 - return audioChannelForReceive;  
350 - }  
351 -  
352 - public void setAudioChannelForReceive(String audioChannelForReceive) {  
353 - this.audioChannelForReceive = audioChannelForReceive;  
354 - }  
355 } 338 }
src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.session;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
  4 +import org.springframework.stereotype.Component;
  5 +
  6 +import java.util.ArrayList;
  7 +import java.util.Collection;
  8 +import java.util.List;
  9 +import java.util.Map;
  10 +import java.util.concurrent.ConcurrentHashMap;
  11 +
  12 +/**
  13 + * 语音广播消息管理类
  14 + * @author lin
  15 + */
  16 +@Component
  17 +public class AudioBroadcastManager {
  18 +
  19 + public static Map<String, AudioBroadcastCatch> data = new ConcurrentHashMap<>();
  20 +
  21 + public void add(AudioBroadcastCatch audioBroadcastCatch) {
  22 + this.update(audioBroadcastCatch);
  23 + }
  24 +
  25 + public void update(AudioBroadcastCatch audioBroadcastCatch) {
  26 + data.put(audioBroadcastCatch.getDeviceId() + audioBroadcastCatch.getChannelId(), audioBroadcastCatch);
  27 + }
  28 +
  29 + public void del(String deviceId, String channelId) {
  30 + data.remove(deviceId + channelId);
  31 + }
  32 +
  33 + public void delByDeviceId(String deviceId) {
  34 + for (String key : data.keySet()) {
  35 + if (key.startsWith(deviceId)) {
  36 + data.remove(key);
  37 + }
  38 + }
  39 + }
  40 +
  41 + public List<AudioBroadcastCatch> getAll(){
  42 + Collection<AudioBroadcastCatch> values = data.values();
  43 + return new ArrayList<>(values);
  44 + }
  45 +
  46 +
  47 + public boolean exit(String deviceId, String channelId) {
  48 + for (String key : data.keySet()) {
  49 + if (key.equals(deviceId + channelId)) {
  50 + return true;
  51 + }
  52 + }
  53 + return false;
  54 + }
  55 +
  56 + public AudioBroadcastCatch get(String deviceId, String channelId) {
  57 + return data.get(deviceId + channelId);
  58 + }
  59 +}
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
@@ -21,9 +21,6 @@ public class CatalogDataCatch { @@ -21,9 +21,6 @@ public class CatalogDataCatch {
21 public static Map<String, CatalogData> data = new ConcurrentHashMap<>(); 21 public static Map<String, CatalogData> data = new ConcurrentHashMap<>();
22 22
23 @Autowired 23 @Autowired
24 - private DeferredResultHolder deferredResultHolder;  
25 -  
26 - @Autowired  
27 private IVideoManagerStorage storager; 24 private IVideoManagerStorage storager;
28 25
29 public void addReady(Device device, int sn ) { 26 public void addReady(Device device, int sn ) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -6,8 +6,12 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; @@ -6,8 +6,12 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; 6 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
7 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 7 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
8 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 8 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  9 +import gov.nist.javax.sip.message.SIPRequest;
  10 +import gov.nist.javax.sip.stack.SIPDialog;
9 11
10 import javax.sip.Dialog; 12 import javax.sip.Dialog;
  13 +import javax.sip.SipException;
  14 +import java.text.ParseException;
11 15
12 /** 16 /**
13 * @description:设备能力接口,用于定义设备的控制、查询能力 17 * @description:设备能力接口,用于定义设备的控制、查询能力
@@ -123,6 +127,7 @@ public interface ISIPCommander { @@ -123,6 +127,7 @@ public interface ISIPCommander {
123 */ 127 */
124 void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent); 128 void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent);
125 void streamByeCmd(String deviceId, String channelId, String stream, String callId); 129 void streamByeCmd(String deviceId, String channelId, String stream, String callId);
  130 + void streamByeCmd(SIPDialog dialog, SIPRequest request, SipSubscribe.Event okEvent) throws SipException, ParseException;
126 131
127 /** 132 /**
128 * 回放暂停 133 * 回放暂停
@@ -144,21 +149,13 @@ public interface ISIPCommander { @@ -144,21 +149,13 @@ public interface ISIPCommander {
144 */ 149 */
145 void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed); 150 void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed);
146 151
147 - /**  
148 - * 语音广播  
149 - *  
150 - * @param device 视频设备  
151 - * @param channelId 预览通道  
152 - */  
153 - boolean audioBroadcastCmd(Device device,String channelId);  
154 152
155 /** 153 /**
156 * 语音广播 154 * 语音广播
157 * 155 *
158 * @param device 视频设备 156 * @param device 视频设备
159 */ 157 */
160 - void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent);  
161 - boolean audioBroadcastCmd(Device device); 158 + boolean audioBroadcastCmd(Device device, String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
162 159
163 /** 160 /**
164 * 音视频录像控制 161 * 音视频录像控制
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -733,42 +733,34 @@ public class SIPCommander implements ISIPCommander { @@ -733,42 +733,34 @@ public class SIPCommander implements ISIPCommander {
733 } 733 }
734 } 734 }
735 735
736 - Request byeRequest = dialog.createRequest(Request.BYE);  
737 - SipURI byeURI = (SipURI) byeRequest.getRequestURI();  
738 - SIPRequest request = (SIPRequest)transaction.getRequest();  
739 - byeURI.setHost(request.getRemoteAddress().getHostAddress());  
740 - byeURI.setPort(request.getRemotePort());  
741 - ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME);  
742 - String protocol = viaHeader.getTransport().toUpperCase();  
743 - ClientTransaction clientTransaction = null;  
744 - if("TCP".equals(protocol)) {  
745 - clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest);  
746 - } else if("UDP".equals(protocol)) {  
747 - clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);  
748 - }  
749 -  
750 - CallIdHeader callIdHeader = (CallIdHeader) byeRequest.getHeader(CallIdHeader.NAME);  
751 - if (okEvent != null) {  
752 - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);  
753 - }  
754 -  
755 - dialog.sendRequest(clientTransaction); 736 + streamByeCmd(dialog, (SIPRequest)transaction.getRequest(), okEvent);
756 737
757 } catch (SipException | ParseException e) { 738 } catch (SipException | ParseException e) {
758 e.printStackTrace(); 739 e.printStackTrace();
759 } 740 }
760 } 741 }
761 742
762 - /**  
763 - * 语音广播  
764 - *  
765 - * @param device 视频设备  
766 - * @param channelId 预览通道  
767 - */  
768 @Override 743 @Override
769 - public boolean audioBroadcastCmd(Device device, String channelId) {  
770 - // 改为新的实现  
771 - return false; 744 + public void streamByeCmd(SIPDialog dialog, SIPRequest request, SipSubscribe.Event okEvent) throws SipException, ParseException {
  745 + Request byeRequest = dialog.createRequest(Request.BYE);
  746 + SipURI byeURI = (SipURI) byeRequest.getRequestURI();
  747 + byeURI.setHost(request.getRemoteAddress().getHostAddress());
  748 + byeURI.setPort(request.getRemotePort());
  749 + ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME);
  750 + String protocol = viaHeader.getTransport().toUpperCase();
  751 + ClientTransaction clientTransaction = null;
  752 + if("TCP".equals(protocol)) {
  753 + clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest);
  754 + } else if("UDP".equals(protocol)) {
  755 + clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
  756 + }
  757 +
  758 + CallIdHeader callIdHeader = (CallIdHeader) byeRequest.getHeader(CallIdHeader.NAME);
  759 + if (okEvent != null) {
  760 + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);
  761 + }
  762 +
  763 + dialog.sendRequest(clientTransaction);
772 } 764 }
773 765
774 /** 766 /**
@@ -777,7 +769,7 @@ public class SIPCommander implements ISIPCommander { @@ -777,7 +769,7 @@ public class SIPCommander implements ISIPCommander {
777 * @param device 视频设备 769 * @param device 视频设备
778 */ 770 */
779 @Override 771 @Override
780 - public boolean audioBroadcastCmd(Device device) { 772 + public boolean audioBroadcastCmd(Device device,String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
781 try { 773 try {
782 StringBuffer broadcastXml = new StringBuffer(200); 774 StringBuffer broadcastXml = new StringBuffer(200);
783 String charset = device.getCharset(); 775 String charset = device.getCharset();
@@ -786,7 +778,7 @@ public class SIPCommander implements ISIPCommander { @@ -786,7 +778,7 @@ public class SIPCommander implements ISIPCommander {
786 broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n"); 778 broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
787 broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); 779 broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
788 broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n"); 780 broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
789 - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n"); 781 + broadcastXml.append("<TargetID>" + channelId + "</TargetID>\r\n");
790 broadcastXml.append("</Notify>\r\n"); 782 broadcastXml.append("</Notify>\r\n");
791 783
792 String tm = Long.toString(System.currentTimeMillis()); 784 String tm = Long.toString(System.currentTimeMillis());
@@ -795,39 +787,14 @@ public class SIPCommander implements ISIPCommander { @@ -795,39 +787,14 @@ public class SIPCommander implements ISIPCommander {
795 : udpSipProvider.getNewCallId(); 787 : udpSipProvider.getNewCallId();
796 788
797 Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), "z9hG4bK-ViaBcst-" + tm, "FromBcst" + tm, null, callIdHeader); 789 Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), "z9hG4bK-ViaBcst-" + tm, "FromBcst" + tm, null, callIdHeader);
798 - transmitRequest(device, request); 790 + transmitRequest(device, request, errorEvent, okEvent);
799 return true; 791 return true;
800 } catch (SipException | ParseException | InvalidArgumentException e) { 792 } catch (SipException | ParseException | InvalidArgumentException e) {
801 e.printStackTrace(); 793 e.printStackTrace();
802 } 794 }
803 return false; 795 return false;
804 } 796 }
805 - @Override  
806 - public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) {  
807 - try {  
808 - StringBuffer broadcastXml = new StringBuffer(200);  
809 - String charset = device.getCharset();  
810 - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
811 - broadcastXml.append("<Notify>\r\n");  
812 - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");  
813 - broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");  
814 - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");  
815 - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");  
816 - broadcastXml.append("</Notify>\r\n");  
817 -  
818 - String tm = Long.toString(System.currentTimeMillis());  
819 797
820 - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()  
821 - : udpSipProvider.getNewCallId();  
822 -  
823 - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), "z9hG4bK-ViaBcst-" + tm, "FromBcst" + tm, null, callIdHeader);  
824 - transmitRequest(device, request, errorEvent);  
825 - } catch (SipException | ParseException | InvalidArgumentException e) {  
826 - e.printStackTrace();  
827 - }  
828 - }  
829 -  
830 -  
831 /** 798 /**
832 * 音视频录像控制 799 * 音视频录像控制
833 * 800 *
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -94,6 +94,9 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -94,6 +94,9 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
94 param.put("dst_port", sendRtpItem.getPort()); 94 param.put("dst_port", sendRtpItem.getPort());
95 param.put("is_udp", is_Udp); 95 param.put("is_udp", is_Udp);
96 param.put("src_port", sendRtpItem.getLocalPort()); 96 param.put("src_port", sendRtpItem.getLocalPort());
  97 + param.put("pt", 8);
  98 + param.put("use_ps", 0);
  99 + param.put("only_audio", 1);
97 zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); 100 zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
98 101
99 102
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -2,21 +2,27 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; @@ -2,21 +2,27 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2
3 import com.alibaba.fastjson.JSONObject; 3 import com.alibaba.fastjson.JSONObject;
4 import com.genersoft.iot.vmp.conf.DynamicTask; 4 import com.genersoft.iot.vmp.conf.DynamicTask;
  5 +import com.genersoft.iot.vmp.conf.SipConfig;
5 import com.genersoft.iot.vmp.conf.UserSetting; 6 import com.genersoft.iot.vmp.conf.UserSetting;
6 import com.genersoft.iot.vmp.gb28181.bean.*; 7 import com.genersoft.iot.vmp.gb28181.bean.*;
7 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 8 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  9 +import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
8 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 10 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
9 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 11 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
  12 +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
  13 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 15 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
12 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 16 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; 17 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 18 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
15 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 19 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  20 +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
16 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; 21 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
17 import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager; 22 import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
18 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 23 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
19 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 24 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  25 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItemLite;
20 import com.genersoft.iot.vmp.service.IMediaServerService; 26 import com.genersoft.iot.vmp.service.IMediaServerService;
21 import com.genersoft.iot.vmp.service.IPlayService; 27 import com.genersoft.iot.vmp.service.IPlayService;
22 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 28 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
@@ -24,8 +30,12 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; @@ -24,8 +30,12 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo;
24 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 30 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
25 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 31 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
26 import com.genersoft.iot.vmp.utils.SerializeUtils; 32 import com.genersoft.iot.vmp.utils.SerializeUtils;
  33 +import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
  34 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
27 import gov.nist.javax.sdp.TimeDescriptionImpl; 35 import gov.nist.javax.sdp.TimeDescriptionImpl;
28 import gov.nist.javax.sdp.fields.TimeField; 36 import gov.nist.javax.sdp.fields.TimeField;
  37 +import gov.nist.javax.sip.message.SIPRequest;
  38 +import gov.nist.javax.sip.stack.SIPDialog;
29 import org.slf4j.Logger; 39 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory; 40 import org.slf4j.LoggerFactory;
31 import org.springframework.beans.factory.InitializingBean; 41 import org.springframework.beans.factory.InitializingBean;
@@ -41,6 +51,7 @@ import javax.sip.message.Response; @@ -41,6 +51,7 @@ import javax.sip.message.Response;
41 import java.text.ParseException; 51 import java.text.ParseException;
42 import java.text.SimpleDateFormat; 52 import java.text.SimpleDateFormat;
43 import java.util.Date; 53 import java.util.Date;
  54 +import java.util.List;
44 import java.util.Vector; 55 import java.util.Vector;
45 56
46 /** 57 /**
@@ -73,7 +84,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -73,7 +84,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
73 private IPlayService playService; 84 private IPlayService playService;
74 85
75 @Autowired 86 @Autowired
76 - private ISIPCommander commander; 87 + private AudioBroadcastManager audioBroadcastManager;
77 88
78 @Autowired 89 @Autowired
79 private ZLMRTPServerFactory zlmrtpServerFactory; 90 private ZLMRTPServerFactory zlmrtpServerFactory;
@@ -93,6 +104,15 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -93,6 +104,15 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
93 @Autowired 104 @Autowired
94 private ZLMMediaListManager mediaListManager; 105 private ZLMMediaListManager mediaListManager;
95 106
  107 + @Autowired
  108 + private DeferredResultHolder resultHolder;
  109 +
  110 + @Autowired
  111 + private ZLMHttpHookSubscribe subscribe;
  112 +
  113 + @Autowired
  114 + private SipConfig config;
  115 +
96 116
97 @Override 117 @Override
98 public void afterPropertiesSet() throws Exception { 118 public void afterPropertiesSet() throws Exception {
@@ -126,7 +146,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -126,7 +146,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
126 // 查询请求是否来自上级平台\设备 146 // 查询请求是否来自上级平台\设备
127 ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId); 147 ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
128 if (platform == null) { 148 if (platform == null) {
129 - inviteFromDeviceHandle(evt, requesterId); 149 + inviteFromDeviceHandle(evt, requesterId, channelId);
130 }else { 150 }else {
131 // 查询平台下是否有该通道 151 // 查询平台下是否有该通道
132 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); 152 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
@@ -542,10 +562,25 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -542,10 +562,25 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
542 } 562 }
543 } 563 }
544 564
545 - public void inviteFromDeviceHandle(RequestEvent evt, String requesterId) throws InvalidArgumentException, ParseException, SipException, SdpException {  
546 - 565 + public void inviteFromDeviceHandle(RequestEvent evt, String requesterId, String channelId) throws InvalidArgumentException, ParseException, SipException, SdpException {
  566 +
  567 + // 兼容奇葩的海康这里使用的不是通道编号而是本平台编号
  568 +// if (channelId.equals(config.getId())) {
  569 +// List<AudioBroadcastCatch> all = audioBroadcastManager.getAll();
  570 +// for (AudioBroadcastCatch audioBroadcastCatch : all) {
  571 +// if (audioBroadcastCatch.getDeviceId().equals(requesterId)) {
  572 +// channelId = audioBroadcastCatch.getChannelId();
  573 +// }
  574 +// }
  575 +// }
  576 +// // 兼容失败
  577 +// if (channelId.equals(config.getId())) {
  578 +// responseAck(evt, Response.BAD_REQUEST);
  579 +// return;
  580 +// }
547 // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备) 581 // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
548 Device device = redisCatchStorage.getDevice(requesterId); 582 Device device = redisCatchStorage.getDevice(requesterId);
  583 +
549 Request request = evt.getRequest(); 584 Request request = evt.getRequest();
550 if (device != null) { 585 if (device != null) {
551 logger.info("收到设备" + requesterId + "的语音广播Invite请求"); 586 logger.info("收到设备" + requesterId + "的语音广播Invite请求");
@@ -558,7 +593,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -558,7 +593,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
558 int ssrcIndex = contentString.indexOf("y="); 593 int ssrcIndex = contentString.indexOf("y=");
559 if (ssrcIndex > 0) { 594 if (ssrcIndex > 0) {
560 substring = contentString.substring(0, ssrcIndex); 595 substring = contentString.substring(0, ssrcIndex);
561 - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); 596 + ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim();
562 } 597 }
563 ssrcIndex = substring.indexOf("f="); 598 ssrcIndex = substring.indexOf("f=");
564 if (ssrcIndex > 0) { 599 if (ssrcIndex > 0) {
@@ -568,6 +603,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -568,6 +603,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
568 603
569 // 获取支持的格式 604 // 获取支持的格式
570 Vector mediaDescriptions = sdp.getMediaDescriptions(true); 605 Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  606 +
571 // 查看是否支持PS 负载96 607 // 查看是否支持PS 负载96
572 int port = -1; 608 int port = -1;
573 //boolean recvonly = false; 609 //boolean recvonly = false;
@@ -602,10 +638,150 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -602,10 +638,150 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
602 responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 638 responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
603 return; 639 return;
604 } 640 }
605 - String username = sdp.getOrigin().getUsername(); 641 + String sessionName = sdp.getSessionName().getValue();
606 String addressStr = sdp.getOrigin().getAddress(); 642 String addressStr = sdp.getOrigin().getAddress();
607 - logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc); 643 + logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", requesterId, addressStr, port, ssrc);
  644 +
  645 + MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device);
  646 + if (mediaServerItem == null) {
  647 + logger.warn("未找到可用的zlm");
  648 + responseAck(evt, Response.BUSY_HERE);
  649 + return;
  650 + }
  651 + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
  652 + device.getDeviceId(), channelId,
  653 + mediaTransmissionTCP);
  654 + sendRtpItem.setTcp(mediaTransmissionTCP);
  655 + if (tcpActive != null) {
  656 + sendRtpItem.setTcpActive(tcpActive);
  657 + }
  658 + if (sendRtpItem == null) {
  659 + logger.warn("服务器端口资源不足");
  660 + responseAck(evt, Response.BUSY_HERE);
  661 + return;
  662 + }
  663 +
  664 + String app = "broadcast";
  665 + String stream = device.getDeviceId() + "_" + channelId;
  666 +
  667 + CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
  668 + sendRtpItem.setPlayType(InviteStreamType.PLAY);
  669 + sendRtpItem.setCallId(callIdHeader.getCallId());
  670 + sendRtpItem.setPlatformId(requesterId);
  671 + sendRtpItem.setStatus(1);
  672 + sendRtpItem.setApp(app);
  673 + sendRtpItem.setStreamId(stream);
  674 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  675 +
  676 + // hook监听等待设备推流上来
  677 + // 添加订阅
  678 + JSONObject subscribeKey = new JSONObject();
  679 + subscribeKey.put("app", app);
  680 + subscribeKey.put("stream", stream);
  681 + subscribeKey.put("regist", true);
  682 + subscribeKey.put("schema", "rtmp");
  683 + subscribeKey.put("mediaServerId", mediaServerItem.getId());
  684 + String finalSsrc = ssrc;
  685 + String waiteStreamTimeoutTaskKey = "waite-stream-" + device.getDeviceId() + channelId;
  686 + if (zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream)) {
  687 + logger.info("发现已经在推流");
  688 + dynamicTask.stop(waiteStreamTimeoutTaskKey);
  689 + sendRtpItem.setStatus(2);
  690 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  691 + StringBuffer content = new StringBuffer(200);
  692 + content.append("v=0\r\n");
  693 + content.append("o="+ config.getId() +" "+ sdp.getOrigin().getSessionId() +" " + sdp.getOrigin().getSessionVersion() + " IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  694 + content.append("s=Play\r\n");
  695 + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  696 + content.append("t=0 0\r\n");
  697 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
  698 + content.append("a=sendonly\r\n");
  699 + content.append("a=rtpmap:8 PCMA/8000\r\n");
  700 + content.append("y="+ finalSsrc + "\r\n");
  701 + content.append("f=v/////a/1/8/1\r\n");
  702 +
  703 + ParentPlatform parentPlatform = new ParentPlatform();
  704 + parentPlatform.setServerIP(device.getIp());
  705 + parentPlatform.setServerPort(device.getPort());
  706 + parentPlatform.setServerGBId(device.getDeviceId());
  707 + try {
  708 + responseSdpAck(evt, content.toString(), parentPlatform);
  709 + } catch (SipException e) {
  710 + throw new RuntimeException(e);
  711 + } catch (InvalidArgumentException e) {
  712 + throw new RuntimeException(e);
  713 + } catch (ParseException e) {
  714 + throw new RuntimeException(e);
  715 + }
  716 + }else {
  717 + // 设置等待推流的超时; 默认20s
  718 + String finalChannelId = channelId;
  719 + dynamicTask.startDelay(waiteStreamTimeoutTaskKey, ()->{
  720 + logger.info("等待推流超时: {}/{}", app, stream);
  721 + if (audioBroadcastManager.exit(device.getDeviceId(), finalChannelId)) {
  722 + audioBroadcastManager.del(device.getDeviceId(), finalChannelId);
  723 + }else {
  724 + // 兼容海康使用了错误的通道ID的情况
  725 + audioBroadcastManager.delByDeviceId(device.getDeviceId());
  726 + }
608 727
  728 + // 发送bye
  729 + try {
  730 + cmder.streamByeCmd((SIPDialog)evt.getServerTransaction().getDialog(), (SIPRequest) evt.getRequest(), null);
  731 + } catch (SipException e) {
  732 + throw new RuntimeException(e);
  733 + } catch (ParseException e) {
  734 + throw new RuntimeException(e);
  735 + }
  736 + }, 20*1000);
  737 +
  738 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  739 + (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  740 + sendRtpItem.setStatus(2);
  741 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  742 + StringBuffer content = new StringBuffer(200);
  743 + content.append("v=0\r\n");
  744 + content.append("o="+ finalChannelId +" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  745 + content.append("s=Play\r\n");
  746 + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  747 + content.append("t=0 0\r\n");
  748 + content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
  749 + content.append("a=sendonly\r\n");
  750 + content.append("a=rtpmap:8 PCMA/8000\r\n");
  751 + content.append("y="+ finalSsrc + "\r\n");
  752 + content.append("f=v/////a/1/8/1\r\n");
  753 +
  754 + ParentPlatform parentPlatform = new ParentPlatform();
  755 + parentPlatform.setServerIP(device.getIp());
  756 + parentPlatform.setServerPort(device.getPort());
  757 + parentPlatform.setServerGBId(device.getDeviceId());
  758 + try {
  759 + responseSdpAck(evt, content.toString(), parentPlatform);
  760 + } catch (SipException e) {
  761 + throw new RuntimeException(e);
  762 + } catch (InvalidArgumentException e) {
  763 + throw new RuntimeException(e);
  764 + } catch (ParseException e) {
  765 + throw new RuntimeException(e);
  766 + }
  767 + });
  768 + }
  769 + String timeOutTaskKey = "audio-broadcast-" + device.getDeviceId() + channelId;
  770 + dynamicTask.stop(timeOutTaskKey);
  771 + String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId();
  772 + WVPResult<AudioBroadcastResult> wvpResult = new WVPResult<>();
  773 + wvpResult.setCode(0);
  774 + wvpResult.setMsg("success");
  775 + AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult();
  776 + audioBroadcastResult.setApp(app);
  777 + audioBroadcastResult.setStream(stream);
  778 + audioBroadcastResult.setMediaServerItem(new MediaServerItemLite(mediaServerItem));
  779 + audioBroadcastResult.setCodec("G.711");
  780 + wvpResult.setData(audioBroadcastResult);
  781 + RequestMessage requestMessage = new RequestMessage();
  782 + requestMessage.setKey(key);
  783 + requestMessage.setData(wvpResult);
  784 + resultHolder.invokeAllResult(requestMessage);
609 } else { 785 } else {
610 logger.warn("来自无效设备/平台的请求"); 786 logger.warn("来自无效设备/平台的请求");
611 responseAck(evt, Response.BAD_REQUEST); 787 responseAck(evt, Response.BAD_REQUEST);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java
@@ -6,7 +6,11 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP @@ -6,7 +6,11 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP
6 import org.dom4j.Element; 6 import org.dom4j.Element;
7 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.beans.factory.annotation.Autowired;
8 8
  9 +import javax.sip.InvalidArgumentException;
9 import javax.sip.RequestEvent; 10 import javax.sip.RequestEvent;
  11 +import javax.sip.SipException;
  12 +import javax.sip.message.Response;
  13 +import java.text.ParseException;
10 import java.util.Map; 14 import java.util.Map;
11 import java.util.concurrent.ConcurrentHashMap; 15 import java.util.concurrent.ConcurrentHashMap;
12 16
@@ -23,6 +27,10 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i @@ -23,6 +27,10 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
23 @Override 27 @Override
24 public void handForDevice(RequestEvent evt, Device device, Element element) { 28 public void handForDevice(RequestEvent evt, Device device, Element element) {
25 String cmd = getText(element, "CmdType"); 29 String cmd = getText(element, "CmdType");
  30 + if (cmd == null) {
  31 + handNullCmd(evt);
  32 + return;
  33 + }
26 IMessageHandler messageHandler = messageHandlerMap.get(cmd); 34 IMessageHandler messageHandler = messageHandlerMap.get(cmd);
27 if (messageHandler != null) { 35 if (messageHandler != null) {
28 messageHandler.handForDevice(evt, device, element); 36 messageHandler.handForDevice(evt, device, element);
@@ -37,4 +45,17 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i @@ -37,4 +45,17 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
37 messageHandler.handForPlatform(evt, parentPlatform, element); 45 messageHandler.handForPlatform(evt, parentPlatform, element);
38 } 46 }
39 } 47 }
  48 +
  49 + public void handNullCmd(RequestEvent evt){
  50 + try {
  51 + responseAck(evt, Response.OK);
  52 + } catch (SipException e) {
  53 + throw new RuntimeException(e);
  54 + } catch (InvalidArgumentException e) {
  55 + throw new RuntimeException(e);
  56 + } catch (ParseException e) {
  57 + throw new RuntimeException(e);
  58 + }
  59 + return;
  60 + }
40 } 61 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
2 2
3 import com.alibaba.fastjson.JSONObject; 3 import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch;
  5 +import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatchStatus;
4 import com.genersoft.iot.vmp.gb28181.bean.Device; 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
5 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 7 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  8 +import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
6 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 9 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
7 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 10 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
8 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
@@ -36,6 +39,9 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i @@ -36,6 +39,9 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i
36 @Autowired 39 @Autowired
37 private DeferredResultHolder deferredResultHolder; 40 private DeferredResultHolder deferredResultHolder;
38 41
  42 + @Autowired
  43 + private AudioBroadcastManager audioBroadcastManager;
  44 +
39 @Override 45 @Override
40 public void afterPropertiesSet() throws Exception { 46 public void afterPropertiesSet() throws Exception {
41 responseMessageHandler.addHandler(cmdType, this); 47 responseMessageHandler.addHandler(cmdType, this);
@@ -45,21 +51,16 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i @@ -45,21 +51,16 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i
45 public void handForDevice(RequestEvent evt, Device device, Element rootElement) { 51 public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
46 try { 52 try {
47 String channelId = getText(rootElement, "DeviceID"); 53 String channelId = getText(rootElement, "DeviceID");
48 - String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId() + channelId;  
49 - // 回复200 OK  
50 - responseAck(evt, Response.OK);  
51 - // 此处是对本平台发出Broadcast指令的应答  
52 - JSONObject json = new JSONObject();  
53 - XmlUtil.node2Json(rootElement, json);  
54 - if (logger.isDebugEnabled()) {  
55 - logger.debug(json.toJSONString()); 54 + if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
  55 + // 回复410
  56 + responseAck(evt, Response.GONE);
  57 + return;
56 } 58 }
57 - RequestMessage msg = new RequestMessage();  
58 - msg.setKey(key);  
59 - msg.setData(json);  
60 - deferredResultHolder.invokeAllResult(msg);  
61 -  
62 - 59 + logger.info("收到语音广播的回复:{}/{}", device.getDeviceId(), channelId );
  60 + AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), channelId);
  61 + audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.WaiteInvite);
  62 + audioBroadcastManager.update(audioBroadcastCatch);
  63 + responseAck(evt, Response.OK);
63 } catch (ParseException | SipException | InvalidArgumentException e) { 64 } catch (ParseException | SipException | InvalidArgumentException e) {
64 e.printStackTrace(); 65 e.printStackTrace();
65 } 66 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -271,7 +271,7 @@ public class ZLMRTPServerFactory { @@ -271,7 +271,7 @@ public class ZLMRTPServerFactory {
271 * 查询待转推的流是否就绪 271 * 查询待转推的流是否就绪
272 */ 272 */
273 public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) { 273 public Boolean isStreamReady(MediaServerItem mediaServerItem, String app, String streamId) {
274 - JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId); 274 + JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtsp", streamId);
275 return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")); 275 return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
276 } 276 }
277 277
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItemLite.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +
  4 +import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
  5 +import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
  6 +import org.springframework.util.StringUtils;
  7 +
  8 +import java.util.HashMap;
  9 +
  10 +/**
  11 + * 精简的MediaServerItem信息,方便给前端返回数据
  12 + */
  13 +public class MediaServerItemLite {
  14 +
  15 + private String id;
  16 +
  17 + private String ip;
  18 +
  19 + private String hookIp;
  20 +
  21 + private String sdpIp;
  22 +
  23 + private String streamIp;
  24 +
  25 + private int httpPort;
  26 +
  27 + private int httpSSlPort;
  28 +
  29 + private int rtmpPort;
  30 +
  31 + private int rtmpSSlPort;
  32 +
  33 + private int rtpProxyPort;
  34 +
  35 + private int rtspPort;
  36 +
  37 + private int rtspSSLPort;
  38 +
  39 + private String secret;
  40 +
  41 + private int streamNoneReaderDelayMS;
  42 +
  43 + private int hookAliveInterval;
  44 +
  45 + private int recordAssistPort;
  46 +
  47 +
  48 +
  49 + public MediaServerItemLite(MediaServerItem mediaServerItem) {
  50 + this.id = mediaServerItem.getId();
  51 + this.ip = mediaServerItem.getIp();
  52 + this.hookIp = mediaServerItem.getHookIp();
  53 + this.sdpIp = mediaServerItem.getSdpIp();
  54 + this.streamIp = mediaServerItem.getStreamIp();
  55 + this.httpPort = mediaServerItem.getHttpPort();
  56 + this.httpSSlPort = mediaServerItem.getHttpSSlPort();
  57 + this.rtmpPort = mediaServerItem.getRtmpPort();
  58 + this.rtmpSSlPort = mediaServerItem.getRtmpSSlPort();
  59 + this.rtpProxyPort = mediaServerItem.getRtpProxyPort();
  60 + this.rtspPort = mediaServerItem.getRtspPort();
  61 + this.rtspSSLPort = mediaServerItem.getRtspSSLPort();
  62 + this.secret = mediaServerItem.getSecret();
  63 + this.streamNoneReaderDelayMS = mediaServerItem.getStreamNoneReaderDelayMS();
  64 + this.hookAliveInterval = mediaServerItem.getHookAliveInterval();
  65 + this.streamNoneReaderDelayMS = mediaServerItem.getStreamNoneReaderDelayMS();
  66 + this.recordAssistPort = mediaServerItem.getRecordAssistPort();
  67 + }
  68 +
  69 + public String getId() {
  70 + return id;
  71 + }
  72 +
  73 + public void setId(String id) {
  74 + this.id = id;
  75 + }
  76 +
  77 + public String getIp() {
  78 + return ip;
  79 + }
  80 +
  81 + public void setIp(String ip) {
  82 + this.ip = ip;
  83 + }
  84 +
  85 + public String getHookIp() {
  86 + return hookIp;
  87 + }
  88 +
  89 + public void setHookIp(String hookIp) {
  90 + this.hookIp = hookIp;
  91 + }
  92 +
  93 + public String getSdpIp() {
  94 + return sdpIp;
  95 + }
  96 +
  97 + public void setSdpIp(String sdpIp) {
  98 + this.sdpIp = sdpIp;
  99 + }
  100 +
  101 + public String getStreamIp() {
  102 + return streamIp;
  103 + }
  104 +
  105 + public void setStreamIp(String streamIp) {
  106 + this.streamIp = streamIp;
  107 + }
  108 +
  109 + public int getHttpPort() {
  110 + return httpPort;
  111 + }
  112 +
  113 + public void setHttpPort(int httpPort) {
  114 + this.httpPort = httpPort;
  115 + }
  116 +
  117 + public int getHttpSSlPort() {
  118 + return httpSSlPort;
  119 + }
  120 +
  121 + public void setHttpSSlPort(int httpSSlPort) {
  122 + this.httpSSlPort = httpSSlPort;
  123 + }
  124 +
  125 + public int getRtmpPort() {
  126 + return rtmpPort;
  127 + }
  128 +
  129 + public void setRtmpPort(int rtmpPort) {
  130 + this.rtmpPort = rtmpPort;
  131 + }
  132 +
  133 + public int getRtmpSSlPort() {
  134 + return rtmpSSlPort;
  135 + }
  136 +
  137 + public void setRtmpSSlPort(int rtmpSSlPort) {
  138 + this.rtmpSSlPort = rtmpSSlPort;
  139 + }
  140 +
  141 + public int getRtpProxyPort() {
  142 + return rtpProxyPort;
  143 + }
  144 +
  145 + public void setRtpProxyPort(int rtpProxyPort) {
  146 + this.rtpProxyPort = rtpProxyPort;
  147 + }
  148 +
  149 + public int getRtspPort() {
  150 + return rtspPort;
  151 + }
  152 +
  153 + public void setRtspPort(int rtspPort) {
  154 + this.rtspPort = rtspPort;
  155 + }
  156 +
  157 + public int getRtspSSLPort() {
  158 + return rtspSSLPort;
  159 + }
  160 +
  161 + public void setRtspSSLPort(int rtspSSLPort) {
  162 + this.rtspSSLPort = rtspSSLPort;
  163 + }
  164 +
  165 +
  166 + public String getSecret() {
  167 + return secret;
  168 + }
  169 +
  170 + public void setSecret(String secret) {
  171 + this.secret = secret;
  172 + }
  173 +
  174 + public int getStreamNoneReaderDelayMS() {
  175 + return streamNoneReaderDelayMS;
  176 + }
  177 +
  178 + public void setStreamNoneReaderDelayMS(int streamNoneReaderDelayMS) {
  179 + this.streamNoneReaderDelayMS = streamNoneReaderDelayMS;
  180 + }
  181 +
  182 + public int getHookAliveInterval() {
  183 + return hookAliveInterval;
  184 + }
  185 +
  186 + public void setHookAliveInterval(int hookAliveInterval) {
  187 + this.hookAliveInterval = hookAliveInterval;
  188 + }
  189 +
  190 + public int getRecordAssistPort() {
  191 + return recordAssistPort;
  192 + }
  193 +
  194 + public void setRecordAssistPort(int recordAssistPort) {
  195 + this.recordAssistPort = recordAssistPort;
  196 + }
  197 +}
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; @@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
11 import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback; 11 import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
12 import com.genersoft.iot.vmp.service.bean.PlayBackCallback; 12 import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
13 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 13 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  14 +import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
14 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; 15 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
15 import org.springframework.http.ResponseEntity; 16 import org.springframework.http.ResponseEntity;
16 import org.springframework.web.context.request.async.DeferredResult; 17 import org.springframework.web.context.request.async.DeferredResult;
@@ -40,4 +41,6 @@ public interface IPlayService { @@ -40,4 +41,6 @@ public interface IPlayService {
40 DeferredResult<ResponseEntity<String>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); 41 DeferredResult<ResponseEntity<String>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
41 42
42 StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream); 43 StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
  44 +
  45 + void audioBroadcast(Device device, String channelId, int timeout, AudioBroadcastEvent event);
43 } 46 }
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask; @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask;
8 import com.genersoft.iot.vmp.conf.UserSetting; 8 import com.genersoft.iot.vmp.conf.UserSetting;
9 import com.genersoft.iot.vmp.gb28181.bean.*; 9 import com.genersoft.iot.vmp.gb28181.bean.*;
10 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 10 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  11 +import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
11 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 12 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
12 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 13 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
13 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 14 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
@@ -26,7 +27,9 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; @@ -26,7 +27,9 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo;
26 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 27 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
27 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 28 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
28 import com.genersoft.iot.vmp.utils.redis.RedisUtil; 29 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  30 +import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
29 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 31 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
  32 +import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
30 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; 33 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
31 import com.genersoft.iot.vmp.service.IMediaService; 34 import com.genersoft.iot.vmp.service.IMediaService;
32 import com.genersoft.iot.vmp.service.IPlayService; 35 import com.genersoft.iot.vmp.service.IPlayService;
@@ -58,6 +61,9 @@ public class PlayServiceImpl implements IPlayService { @@ -58,6 +61,9 @@ public class PlayServiceImpl implements IPlayService {
58 private SIPCommander cmder; 61 private SIPCommander cmder;
59 62
60 @Autowired 63 @Autowired
  64 + private AudioBroadcastManager audioBroadcastManager;
  65 +
  66 + @Autowired
61 private SIPCommanderFroPlatform sipCommanderFroPlatform; 67 private SIPCommanderFroPlatform sipCommanderFroPlatform;
62 68
63 @Autowired 69 @Autowired
@@ -621,4 +627,42 @@ public class PlayServiceImpl implements IPlayService { @@ -621,4 +627,42 @@ public class PlayServiceImpl implements IPlayService {
621 } 627 }
622 } 628 }
623 } 629 }
  630 +
  631 + @Override
  632 + public void audioBroadcast(Device device, String channelId, int timeout, AudioBroadcastEvent event) {
  633 + if (device == null || channelId == null) {
  634 + return;
  635 + }
  636 + DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
  637 + if (deviceChannel == null) {
  638 + logger.warn("开启语音广播的时候未找到通道: {}", channelId);
  639 + event.call("开启语音广播的时候未找到通道");
  640 + return;
  641 + }
  642 + // 查询通道使用状态
  643 + if (audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
  644 + logger.warn("语音广播已经开启: {}", channelId);
  645 + event.call("语音广播已经开启");
  646 + return;
  647 + }
  648 + String timeOutTaskKey = "audio-broadcast-" + device.getDeviceId() + channelId;
  649 + dynamicTask.startDelay(timeOutTaskKey, ()->{
  650 + logger.error("语音广播发送超时: {}:{}", device.getDeviceId(), channelId);
  651 + event.call("语音广播发送超时");
  652 + audioBroadcastManager.del(device.getDeviceId(), channelId);
  653 + }, timeout * 1000);
  654 +
  655 + // 发送通知
  656 + cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> {
  657 + // 发送成功
  658 + AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId, AudioBroadcastCatchStatus.Ready);
  659 + audioBroadcastManager.add(audioBroadcastCatch);
  660 + }, eventResultForError -> {
  661 + dynamicTask.stop(timeOutTaskKey);
  662 + // 发送失败
  663 + logger.error("语音广播发送失败: {}:{}", channelId, eventResultForError.msg);
  664 + event.call("语音广播发送失败");
  665 + audioBroadcastManager.del(device.getDeviceId(), channelId);
  666 + });
  667 + }
624 } 668 }
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
@@ -37,8 +37,6 @@ public interface DeviceMapper { @@ -37,8 +37,6 @@ public interface DeviceMapper {
37 "subscribeCycleForMobilePosition," + 37 "subscribeCycleForMobilePosition," +
38 "mobilePositionSubmissionInterval," + 38 "mobilePositionSubmissionInterval," +
39 "subscribeCycleForAlarm," + 39 "subscribeCycleForAlarm," +
40 - "audioChannelForReceive," +  
41 - "audioChannelForSend," +  
42 "ssrcCheck," + 40 "ssrcCheck," +
43 "online" + 41 "online" +
44 ") VALUES (" + 42 ") VALUES (" +
@@ -62,8 +60,6 @@ public interface DeviceMapper { @@ -62,8 +60,6 @@ public interface DeviceMapper {
62 "#{subscribeCycleForMobilePosition}," + 60 "#{subscribeCycleForMobilePosition}," +
63 "#{mobilePositionSubmissionInterval}," + 61 "#{mobilePositionSubmissionInterval}," +
64 "#{subscribeCycleForAlarm}," + 62 "#{subscribeCycleForAlarm}," +
65 - "#{audioChannelForReceive}," +  
66 - "#{audioChannelForSend}," +  
67 "#{ssrcCheck}," + 63 "#{ssrcCheck}," +
68 "#{online}" + 64 "#{online}" +
69 ")") 65 ")")
@@ -90,8 +86,6 @@ public interface DeviceMapper { @@ -90,8 +86,6 @@ public interface DeviceMapper {
90 "<if test=\"subscribeCycleForMobilePosition != null\">, subscribeCycleForMobilePosition=${subscribeCycleForMobilePosition}</if>" + 86 "<if test=\"subscribeCycleForMobilePosition != null\">, subscribeCycleForMobilePosition=${subscribeCycleForMobilePosition}</if>" +
91 "<if test=\"mobilePositionSubmissionInterval != null\">, mobilePositionSubmissionInterval=${mobilePositionSubmissionInterval}</if>" + 87 "<if test=\"mobilePositionSubmissionInterval != null\">, mobilePositionSubmissionInterval=${mobilePositionSubmissionInterval}</if>" +
92 "<if test=\"subscribeCycleForAlarm != null\">, subscribeCycleForAlarm=${subscribeCycleForAlarm}</if>" + 88 "<if test=\"subscribeCycleForAlarm != null\">, subscribeCycleForAlarm=${subscribeCycleForAlarm}</if>" +
93 - "<if test=\"audioChannelForReceive != null\">, audioChannelForReceive=#{audioChannelForReceive}</if>" +  
94 - "<if test=\"audioChannelForSend != null\">, audioChannelForSend=#{audioChannelForSend}</if>" +  
95 "<if test=\"ssrcCheck != null\">, ssrcCheck=${ssrcCheck}</if>" + 89 "<if test=\"ssrcCheck != null\">, ssrcCheck=${ssrcCheck}</if>" +
96 "WHERE deviceId='${deviceId}'"+ 90 "WHERE deviceId='${deviceId}'"+
97 " </script>"}) 91 " </script>"})
src/main/java/com/genersoft/iot/vmp/vmanager/bean/AudioBroadcastResult.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.bean;
  2 +
  3 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItemLite;
  5 +
  6 +/**
  7 + * @author lin
  8 + */
  9 +public class AudioBroadcastResult {
  10 + /**
  11 + * 推流的媒体节点信息
  12 + */
  13 + private MediaServerItemLite mediaServerItem;
  14 +
  15 + /**
  16 + * 编码格式
  17 + */
  18 + private String codec;
  19 +
  20 + /**
  21 + * 向zlm推流的应用名
  22 + */
  23 + private String app;
  24 +
  25 + /**
  26 + * 向zlm推流的流ID
  27 + */
  28 + private String stream;
  29 +
  30 +
  31 + public MediaServerItemLite getMediaServerItem() {
  32 + return mediaServerItem;
  33 + }
  34 +
  35 + public void setMediaServerItem(MediaServerItemLite mediaServerItem) {
  36 + this.mediaServerItem = mediaServerItem;
  37 + }
  38 +
  39 + public String getCodec() {
  40 + return codec;
  41 + }
  42 +
  43 + public void setCodec(String codec) {
  44 + this.codec = codec;
  45 + }
  46 +
  47 + public String getApp() {
  48 + return app;
  49 + }
  50 +
  51 + public void setApp(String app) {
  52 + this.app = app;
  53 + }
  54 +
  55 + public String getStream() {
  56 + return stream;
  57 + }
  58 +
  59 + public void setStream(String stream) {
  60 + this.stream = stream;
  61 + }
  62 +}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; @@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 import com.genersoft.iot.vmp.service.IMediaServerService; 12 import com.genersoft.iot.vmp.service.IMediaServerService;
13 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 13 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  14 +import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
14 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 15 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
15 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; 16 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
16 import com.genersoft.iot.vmp.service.IMediaService; 17 import com.genersoft.iot.vmp.service.IMediaService;
@@ -39,6 +40,9 @@ import org.springframework.web.context.request.async.DeferredResult; @@ -39,6 +40,9 @@ import org.springframework.web.context.request.async.DeferredResult;
39 import java.util.List; 40 import java.util.List;
40 import java.util.UUID; 41 import java.util.UUID;
41 42
  43 +/**
  44 + * @author lin
  45 + */
42 @Api(tags = "国标设备点播") 46 @Api(tags = "国标设备点播")
43 @CrossOrigin 47 @CrossOrigin
44 @RestController 48 @RestController
@@ -102,7 +106,7 @@ public class PlayController { @@ -102,7 +106,7 @@ public class PlayController {
102 logger.debug(String.format("设备预览/回放停止API调用,streamId:%s_%s", deviceId, channelId )); 106 logger.debug(String.format("设备预览/回放停止API调用,streamId:%s_%s", deviceId, channelId ));
103 107
104 String uuid = UUID.randomUUID().toString(); 108 String uuid = UUID.randomUUID().toString();
105 - DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(); 109 + DeferredResult<ResponseEntity<String>> result = new DeferredResult<>();
106 110
107 // 录像查询以channelId作为deviceId查询 111 // 录像查询以channelId作为deviceId查询
108 String key = DeferredResultHolder.CALLBACK_CMD_STOP + deviceId + channelId; 112 String key = DeferredResultHolder.CALLBACK_CMD_STOP + deviceId + channelId;
@@ -123,7 +127,7 @@ public class PlayController { @@ -123,7 +127,7 @@ public class PlayController {
123 RequestMessage msgForSuccess = new RequestMessage(); 127 RequestMessage msgForSuccess = new RequestMessage();
124 msgForSuccess.setId(uuid); 128 msgForSuccess.setId(uuid);
125 msgForSuccess.setKey(key); 129 msgForSuccess.setKey(key);
126 - msgForSuccess.setData(String.format("success")); 130 + msgForSuccess.setData("success");
127 resultHolder.invokeAllResult(msgForSuccess); 131 resultHolder.invokeAllResult(msgForSuccess);
128 }); 132 });
129 133
@@ -251,81 +255,73 @@ public class PlayController { @@ -251,81 +255,73 @@ public class PlayController {
251 @ApiOperation("语音广播命令") 255 @ApiOperation("语音广播命令")
252 @ApiImplicitParams({ 256 @ApiImplicitParams({
253 @ApiImplicitParam(name = "deviceId", value = "设备Id", dataTypeClass = String.class), 257 @ApiImplicitParam(name = "deviceId", value = "设备Id", dataTypeClass = String.class),
254 - @ApiImplicitParam(name = "channelForSend", value = "设备用于发送语音数据的通道", dataTypeClass = String.class),  
255 - @ApiImplicitParam(name = "channelForReceive", value = "设备用于接收语音数据的通道", dataTypeClass = String.class), 258 + @ApiImplicitParam(name = "channelId", value = "通道Id", dataTypeClass = String.class),
  259 + @ApiImplicitParam(name = "timeout", value = "推流超时时间(秒)", dataTypeClass = Integer.class),
256 }) 260 })
257 - @GetMapping("/broadcast/{deviceId}")  
258 - @PostMapping("/broadcast/{deviceId}")  
259 - public DeferredResult<ResponseEntity<String>> broadcastApi(@PathVariable String deviceId,  
260 - String channelForSend,  
261 - String channelForReceive) { 261 + @GetMapping("/broadcast/{deviceId}/{channelId}")
  262 + @PostMapping("/broadcast/{deviceId}/{channelId}")
  263 + public DeferredResult<WVPResult<AudioBroadcastResult>> broadcastApi(@PathVariable String deviceId, @PathVariable String channelId, Integer timeout) {
262 if (logger.isDebugEnabled()) { 264 if (logger.isDebugEnabled()) {
263 logger.debug("语音广播API调用"); 265 logger.debug("语音广播API调用");
264 } 266 }
265 Device device = storager.queryVideoDevice(deviceId); 267 Device device = storager.queryVideoDevice(deviceId);
266 - DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(3 * 1000L);  
267 - String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId;  
268 - if (resultHolder.exist(key, null)) {  
269 - result.setResult(new ResponseEntity<>("设备使用中",HttpStatus.OK));  
270 - return result; 268 + if (device == null) {
  269 + WVPResult<AudioBroadcastResult> result = new WVPResult<>();
  270 + result.setCode(-1);
  271 + result.setMsg("未找到设备: " + deviceId);
  272 + DeferredResult<WVPResult<AudioBroadcastResult>> deferredResult = new DeferredResult<>();
  273 + deferredResult.setResult(result);
  274 + return deferredResult;
  275 + }
  276 + if (channelId == null) {
  277 + WVPResult<AudioBroadcastResult> result = new WVPResult<>();
  278 + result.setCode(-1);
  279 + result.setMsg("未找到通道: " + channelId);
  280 + DeferredResult<WVPResult<AudioBroadcastResult>> deferredResult = new DeferredResult<>();
  281 + deferredResult.setResult(result);
  282 + return deferredResult;
271 } 283 }
272 284
273 -// playService.audioBroadcast(deviceId, channelForSend, channelForReceive);  
274 -  
275 -  
276 -  
277 -  
278 -  
279 -  
280 - String uuid = UUID.randomUUID().toString();  
281 - if (device == null) {  
282 -  
283 - resultHolder.put(key, key, result);  
284 - RequestMessage msg = new RequestMessage();  
285 - msg.setKey(key);  
286 - msg.setId(uuid);  
287 - JSONObject json = new JSONObject();  
288 - json.put("DeviceID", deviceId);  
289 - json.put("CmdType", "Broadcast");  
290 - json.put("Result", "Failed");  
291 - json.put("Description", "Device 不存在");  
292 - msg.setData(json);  
293 - resultHolder.invokeResult(msg);  
294 - return result; 285 + String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId;
  286 + if (resultHolder.exist(key, null)) {
  287 + WVPResult<AudioBroadcastResult> wvpResult = new WVPResult<>();
  288 + wvpResult.setCode(-1);
  289 + wvpResult.setMsg("设备使用中");
  290 + DeferredResult<WVPResult<AudioBroadcastResult>> deferredResult = new DeferredResult<>();
  291 + deferredResult.setResult(wvpResult);
  292 + return deferredResult;
295 } 293 }
296 - cmder.audioBroadcastCmd(device, (event) -> {  
297 - RequestMessage msg = new RequestMessage();  
298 - msg.setKey(key);  
299 - msg.setId(uuid);  
300 - JSONObject json = new JSONObject();  
301 - json.put("DeviceID", deviceId);  
302 - json.put("CmdType", "Broadcast");  
303 - json.put("Result", "Failed");  
304 - json.put("Description", String.format("语音广播操作失败,错误码: %s, %s", event.statusCode, event.msg));  
305 - msg.setData(json);  
306 - resultHolder.invokeResult(msg); 294 + if (timeout == null){
  295 + timeout = 30;
  296 + }
  297 + DeferredResult<WVPResult<AudioBroadcastResult>> result = new DeferredResult<>(timeout.longValue()*1000 + 2000);
  298 + String uuid = UUID.randomUUID().toString();
  299 + result.onTimeout(()->{
  300 + WVPResult<AudioBroadcastResult> wvpResult = new WVPResult<>();
  301 + wvpResult.setCode(-1);
  302 + wvpResult.setMsg("请求超时");
  303 + RequestMessage requestMessage = new RequestMessage();
  304 + requestMessage.setKey(key);
  305 + requestMessage.setData(wvpResult);
  306 + resultHolder.invokeAllResult(requestMessage);
307 }); 307 });
308 -  
309 - result.onTimeout(() -> {  
310 - logger.warn(String.format("语音广播操作超时, 设备未返回应答指令"));  
311 - RequestMessage msg = new RequestMessage();  
312 - msg.setKey(key);  
313 - msg.setId(uuid);  
314 - JSONObject json = new JSONObject();  
315 - json.put("DeviceID", deviceId);  
316 - json.put("CmdType", "Broadcast");  
317 - json.put("Result", "Failed");  
318 - json.put("Error", "Timeout. Device did not response to broadcast command.");  
319 - msg.setData(json);  
320 - resultHolder.invokeResult(msg); 308 + playService.audioBroadcast(device, channelId, timeout, (msg)->{
  309 + WVPResult<AudioBroadcastResult> wvpResult = new WVPResult<>();
  310 + wvpResult.setCode(-1);
  311 + wvpResult.setMsg(msg);
  312 + RequestMessage requestMessage = new RequestMessage();
  313 + requestMessage.setKey(key);
  314 + requestMessage.setData(wvpResult);
  315 + resultHolder.invokeAllResult(requestMessage);
321 }); 316 });
322 resultHolder.put(key, uuid, result); 317 resultHolder.put(key, uuid, result);
  318 +
323 return result; 319 return result;
324 } 320 }
325 321
326 @ApiOperation("获取所有的ssrc") 322 @ApiOperation("获取所有的ssrc")
327 @GetMapping("/ssrc") 323 @GetMapping("/ssrc")
328 - public WVPResult<JSONObject> getSSRC() { 324 + public WVPResult<JSONObject> getSsrc() {
329 if (logger.isDebugEnabled()) { 325 if (logger.isDebugEnabled()) {
330 logger.debug("获取所有的ssrc"); 326 logger.debug("获取所有的ssrc");
331 } 327 }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/AudioBroadcastEvent.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.gb28181.play.bean;
  2 +
  3 +
  4 +/**
  5 + * @author lin
  6 + */
  7 +public interface AudioBroadcastEvent {
  8 + void call(String msg);
  9 +}
web_src/src/components/dialog/deviceEdit.vue
@@ -37,9 +37,6 @@ @@ -37,9 +37,6 @@
37 </el-select> 37 </el-select>
38 </el-form-item> 38 </el-form-item>
39 <el-form-item label="语音发送通道" prop="name"> 39 <el-form-item label="语音发送通道" prop="name">
40 - <el-input v-model="form.audioChannelForSend" clearable></el-input>  
41 - </el-form-item>  
42 - <el-form-item label="语音接收送通道" prop="name">  
43 <el-input v-model="form.audioChannelForReceive" clearable></el-input> 40 <el-input v-model="form.audioChannelForReceive" clearable></el-input>
44 </el-form-item> 41 </el-form-item>
45 <el-form-item label="目录订阅" title="0为取消订阅" prop="subscribeCycleForCatalog" > 42 <el-form-item label="目录订阅" title="0为取消订阅" prop="subscribeCycleForCatalog" >
@@ -105,6 +102,8 @@ export default { @@ -105,6 +102,8 @@ export default {
105 }) 102 })
106 }, 103 },
107 onSubmit: function () { 104 onSubmit: function () {
  105 + console.log("onSubmit");
  106 + console.log(this.form);
108 this.form.subscribeCycleForCatalog = this.form.subscribeCycleForCatalog||0 107 this.form.subscribeCycleForCatalog = this.form.subscribeCycleForCatalog||0
109 this.form.subscribeCycleForMobilePosition = this.form.subscribeCycleForMobilePosition||0 108 this.form.subscribeCycleForMobilePosition = this.form.subscribeCycleForMobilePosition||0
110 this.form.mobilePositionSubmissionInterval = this.form.mobilePositionSubmissionInterval||0 109 this.form.mobilePositionSubmissionInterval = this.form.mobilePositionSubmissionInterval||0
@@ -124,7 +123,7 @@ export default { @@ -124,7 +123,7 @@ export default {
124 }); 123 });
125 } 124 }
126 }).catch(function (error) { 125 }).catch(function (error) {
127 - console.error(error); 126 + console.log(error);
128 }); 127 });
129 }, 128 },
130 close: function () { 129 close: function () {