Commit 06bbe3fe01e5af9486c309693a975077df813f7c

Authored by 648540858
1 parent ebe8667b

添加第二种语音对讲实现

Showing 29 changed files with 876 additions and 576 deletions
@@ -273,7 +273,6 @@ @@ -273,7 +273,6 @@
273 <dateFormat>yyyyMMdd</dateFormat> 273 <dateFormat>yyyyMMdd</dateFormat>
274 </configuration> 274 </configuration>
275 </plugin> 275 </plugin>
276 -  
277 <plugin> 276 <plugin>
278 <groupId>org.apache.maven.plugins</groupId> 277 <groupId>org.apache.maven.plugins</groupId>
279 <artifactId>maven-surefire-plugin</artifactId> 278 <artifactId>maven-surefire-plugin</artifactId>
@@ -282,7 +281,6 @@ @@ -282,7 +281,6 @@
282 <skipTests>true</skipTests> 281 <skipTests>true</skipTests>
283 </configuration> 282 </configuration>
284 </plugin> 283 </plugin>
285 -  
286 </plugins> 284 </plugins>
287 <resources> 285 <resources>
288 <resource> 286 <resource>
src/main/java/com/genersoft/iot/vmp/conf/exception/SsrcTransactionNotFoundException.java
@@ -39,12 +39,12 @@ public class SsrcTransactionNotFoundException extends Exception{ @@ -39,12 +39,12 @@ public class SsrcTransactionNotFoundException extends Exception{
39 @Override 39 @Override
40 public String getMessage() { 40 public String getMessage() {
41 StringBuffer msg = new StringBuffer(); 41 StringBuffer msg = new StringBuffer();
42 - msg.append(StringFormatter.format("缓存事务信息未找到,device:%s channel: %s ", deviceId, channelId)); 42 + msg.append(String.format("缓存事务信息未找到,device:%s channel: %s ", deviceId, channelId));
43 if (callId != null) { 43 if (callId != null) {
44 - msg.append("callId: " + callId); 44 + msg.append(",callId: " + callId);
45 } 45 }
46 if (stream != null) { 46 if (stream != null) {
47 - msg.append("stream: " + stream); 47 + msg.append(",stream: " + stream);
48 } 48 }
49 return msg.toString(); 49 return msg.toString();
50 } 50 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean; @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 3
4 import gov.nist.javax.sip.message.SIPRequest; 4 import gov.nist.javax.sip.message.SIPRequest;
  5 +import gov.nist.javax.sip.message.SIPResponse;
5 import gov.nist.javax.sip.stack.SIPDialog; 6 import gov.nist.javax.sip.stack.SIPDialog;
6 7
7 import javax.sip.Dialog; 8 import javax.sip.Dialog;
@@ -40,12 +41,7 @@ public class AudioBroadcastCatch { @@ -40,12 +41,7 @@ public class AudioBroadcastCatch {
40 /** 41 /**
41 * 请求信息 42 * 请求信息
42 */ 43 */
43 - private SIPRequest request;  
44 -  
45 - /**  
46 - * 会话信息  
47 - */  
48 - private SIPDialog dialog; 44 + private SipTransactionInfo sipTransactionInfo;
49 45
50 46
51 public String getDeviceId() { 47 public String getDeviceId() {
@@ -72,19 +68,15 @@ public class AudioBroadcastCatch { @@ -72,19 +68,15 @@ public class AudioBroadcastCatch {
72 this.status = status; 68 this.status = status;
73 } 69 }
74 70
75 - public void setDialog(SIPDialog dialog) {  
76 - this.dialog = dialog;  
77 - }  
78 -  
79 - public SIPDialog getDialog() {  
80 - return dialog; 71 + public SipTransactionInfo getSipTransactionInfo() {
  72 + return sipTransactionInfo;
81 } 73 }
82 74
83 - public SIPRequest getRequest() {  
84 - return request; 75 + public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
  76 + this.sipTransactionInfo = sipTransactionInfo;
85 } 77 }
86 78
87 - public void setRequest(SIPRequest request) {  
88 - this.request = request; 79 + public void setSipTransactionInfoByRequset(SIPResponse response) {
  80 + this.sipTransactionInfo = new SipTransactionInfo(response);
89 } 81 }
90 } 82 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java
@@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean; @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 public enum InviteStreamType { 3 public enum InviteStreamType {
4 4
5 - PLAY,PLAYBACK,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY 5 + PLAY,PLAYBACK,PUSH,PROXY,CLOUD_RECORD_PUSH,CLOUD_RECORD_PROXY,TALK
6 6
7 7
8 } 8 }
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
1 package com.genersoft.iot.vmp.gb28181.event; 1 package com.genersoft.iot.vmp.gb28181.event;
2 2
  3 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
3 import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent; 4 import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent;
4 import gov.nist.javax.sip.message.SIPRequest; 5 import gov.nist.javax.sip.message.SIPRequest;
5 import org.slf4j.Logger; 6 import org.slf4j.Logger;
@@ -57,7 +58,7 @@ public class SipSubscribe { @@ -57,7 +58,7 @@ public class SipSubscribe {
57 logger.debug("errorSubscribes.size:{}",errorSubscribes.size()); 58 logger.debug("errorSubscribes.size:{}",errorSubscribes.size());
58 } 59 }
59 60
60 - public interface Event { void response(EventResult eventResult) ; 61 + public interface Event { void response(EventResult eventResult);
61 } 62 }
62 63
63 /** 64 /**
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -8,18 +8,12 @@ import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; @@ -8,18 +8,12 @@ import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
8 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 8 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
9 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 9 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
10 import gov.nist.javax.sip.message.SIPRequest; 10 import gov.nist.javax.sip.message.SIPRequest;
11 -import gov.nist.javax.sip.message.SIPRequest;  
12 -import gov.nist.javax.sip.stack.SIPDialog;  
13 11
14 -import javax.sip.Dialog;  
15 -import javax.sip.InvalidArgumentException;  
16 -import javax.sip.SipException;  
17 -import java.text.ParseException;  
18 import javax.sip.InvalidArgumentException; 12 import javax.sip.InvalidArgumentException;
19 import javax.sip.PeerUnavailableException; 13 import javax.sip.PeerUnavailableException;
20 import javax.sip.SipException; 14 import javax.sip.SipException;
21 -import javax.sip.message.Request;  
22 import java.text.ParseException; 15 import java.text.ParseException;
  16 +import javax.sip.message.Request;
23 17
24 /** 18 /**
25 * @description:设备能力接口,用于定义设备的控制、查询能力 19 * @description:设备能力接口,用于定义设备的控制、查询能力
@@ -130,14 +124,18 @@ public interface ISIPCommander { @@ -130,14 +124,18 @@ public interface ISIPCommander {
130 String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, 124 String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
131 SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; 125 SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
132 126
  127 +
133 /** 128 /**
134 * 视频流停止 129 * 视频流停止
135 */ 130 */
136 - void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent);  
137 - void streamByeCmd(String deviceId, String channelId, String stream, String callId);  
138 void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; 131 void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
  132 +
  133 + void talkStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  134 +
139 void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException; 135 void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
140 136
  137 + void streamByeCmd(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
  138 +
141 /** 139 /**
142 * 回放暂停 140 * 回放暂停
143 */ 141 */
@@ -168,22 +166,12 @@ public interface ISIPCommander { @@ -168,22 +166,12 @@ public interface ISIPCommander {
168 166
169 167
170 /** 168 /**
171 -  
172 - /**  
173 - * 语音广播  
174 - *  
175 - * @param device 视频设备  
176 - */  
177 - boolean audioBroadcastCmd(Device device, String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);  
178 - void audioBroadcastCmd(Device device,String channelId);  
179 -  
180 - /** 169 + * /**
181 * 语音广播 170 * 语音广播
182 * 171 *
183 - * @param device 视频设备 172 + * @param device 视频设备
184 */ 173 */
185 - void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;  
186 - void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException; 174 + void audioBroadcastCmd(Device device, String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
187 175
188 /** 176 /**
189 * 音视频录像控制 177 * 音视频录像控制
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
@@ -326,4 +326,37 @@ public class SIPRequestHeaderProvider { @@ -326,4 +326,37 @@ public class SIPRequestHeaderProvider {
326 326
327 return request; 327 return request;
328 } 328 }
  329 +
  330 + public Request createBroadcastMessageRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  331 + Request request = null;
  332 + // sipuri
  333 + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
  334 + // via
  335 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  336 + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
  337 + viaHeader.setRPort();
  338 + viaHeaders.add(viaHeader);
  339 + // from
  340 + SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  341 + Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
  342 + FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
  343 + // to
  344 + SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
  345 + Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
  346 + ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
  347 +
  348 + // Forwards
  349 + MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
  350 + // ceq
  351 + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);
  352 +
  353 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  354 +
  355 + request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
  356 + toHeader, viaHeaders, maxForwards, contentTypeHeader, content);
  357 +
  358 + request.addHeader(SipUtils.createUserAgentHeader(sipFactory, gitUtil));
  359 +
  360 + return request;
  361 + }
329 } 362 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; @@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
2 2
3 import com.alibaba.fastjson.JSONObject; 3 import com.alibaba.fastjson.JSONObject;
4 import com.genersoft.iot.vmp.common.StreamInfo; 4 import com.genersoft.iot.vmp.common.StreamInfo;
5 -import com.genersoft.iot.vmp.conf.DynamicTask;  
6 import com.genersoft.iot.vmp.conf.SipConfig; 5 import com.genersoft.iot.vmp.conf.SipConfig;
7 import com.genersoft.iot.vmp.conf.UserSetting; 6 import com.genersoft.iot.vmp.conf.UserSetting;
8 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
@@ -12,45 +11,32 @@ import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; @@ -12,45 +11,32 @@ import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
12 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
13 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; 12 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
14 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 13 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  14 +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
15 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; 15 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
16 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; 16 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  17 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamPush;
17 import com.genersoft.iot.vmp.utils.DateUtil; 18 import com.genersoft.iot.vmp.utils.DateUtil;
18 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; 19 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
19 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 20 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
20 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 21 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
21 import com.genersoft.iot.vmp.service.IMediaServerService; 22 import com.genersoft.iot.vmp.service.IMediaServerService;
22 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 23 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
23 -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;  
24 -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;  
25 import com.genersoft.iot.vmp.utils.GitUtil; 24 import com.genersoft.iot.vmp.utils.GitUtil;
26 -import gov.nist.javax.sip.SIPConstants;  
27 import gov.nist.javax.sip.SipProviderImpl; 25 import gov.nist.javax.sip.SipProviderImpl;
28 -import gov.nist.javax.sip.SipStackImpl;  
29 import gov.nist.javax.sip.message.SIPRequest; 26 import gov.nist.javax.sip.message.SIPRequest;
30 import gov.nist.javax.sip.message.SIPResponse; 27 import gov.nist.javax.sip.message.SIPResponse;
31 -import gov.nist.javax.sip.stack.SIPClientTransaction;  
32 -import gov.nist.javax.sip.stack.SIPClientTransactionImpl;  
33 -import gov.nist.javax.sip.stack.SIPDialog;  
34 import org.slf4j.Logger; 28 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory; 29 import org.slf4j.LoggerFactory;
36 import org.springframework.beans.factory.annotation.Autowired; 30 import org.springframework.beans.factory.annotation.Autowired;
37 import org.springframework.beans.factory.annotation.Qualifier; 31 import org.springframework.beans.factory.annotation.Qualifier;
38 import org.springframework.context.annotation.DependsOn; 32 import org.springframework.context.annotation.DependsOn;
39 -import org.springframework.context.annotation.Lazy;  
40 import org.springframework.stereotype.Component; 33 import org.springframework.stereotype.Component;
41 import org.springframework.util.ObjectUtils; 34 import org.springframework.util.ObjectUtils;
42 35
43 import javax.sip.*; 36 import javax.sip.*;
44 -import javax.sip.address.Address;  
45 -import javax.sip.address.SipURI;  
46 import javax.sip.header.*; 37 import javax.sip.header.*;
47 import javax.sip.message.Request; 38 import javax.sip.message.Request;
48 -import javax.sip.message.Response;  
49 -import java.lang.reflect.Field;  
50 import java.text.ParseException; 39 import java.text.ParseException;
51 -import java.util.ArrayList;  
52 -import java.util.HashSet;  
53 -import java.util.List;  
54 40
55 /** 41 /**
56 * @description:设备能力接口,用于定义设备的控制、查询能力 42 * @description:设备能力接口,用于定义设备的控制、查询能力
@@ -98,6 +84,9 @@ public class SIPCommander implements ISIPCommander { @@ -98,6 +84,9 @@ public class SIPCommander implements ISIPCommander {
98 @Autowired 84 @Autowired
99 private IMediaServerService mediaServerService; 85 private IMediaServerService mediaServerService;
100 86
  87 + @Autowired
  88 + private ZLMRTPServerFactory zlmrtpServerFactory;
  89 +
101 90
102 /** 91 /**
103 * 云台方向放控制,使用配置文件中的默认镜头移动速度 92 * 云台方向放控制,使用配置文件中的默认镜头移动速度
@@ -591,11 +580,73 @@ public class SIPCommander implements ISIPCommander { @@ -591,11 +580,73 @@ public class SIPCommander implements ISIPCommander {
591 }); 580 });
592 } 581 }
593 582
  583 + @Override
  584 + public void talkStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  585 +
  586 + String stream = ssrcInfo.getStream();
  587 +
  588 + if (device == null) {
  589 + return;
  590 + }
  591 + if (!mediaServerItem.isRtpEnable()) {
  592 + // 单端口暂不支持语音对讲
  593 + logger.info("[语音对讲] 单端口暂不支持此操作");
  594 + return;
  595 + }
  596 +
  597 + logger.info("[语音对讲] {} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
  598 + HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
  599 + subscribe.addSubscribe(hookSubscribeForStreamChange, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
  600 + if (event != null) {
  601 + event.response(mediaServerItemInUse, json);
  602 + subscribe.removeSubscribe(hookSubscribeForStreamChange);
  603 + }
  604 + });
  605 +
  606 + CallIdHeader callIdHeader = device.getTransport().equalsIgnoreCase("TCP") ? tcpSipProvider.getNewCallId()
  607 + : udpSipProvider.getNewCallId();
  608 + callIdHeader.setCallId(callId);
  609 + HookSubscribeForStreamPush hookSubscribeForStreamPush = HookSubscribeFactory.on_publish("rtp", stream, null, mediaServerItem.getId());
  610 + subscribe.addSubscribe(hookSubscribeForStreamPush, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
  611 + if (eventForPush != null) {
  612 + eventForPush.response(mediaServerItemInUse, json);
  613 + }
  614 + });
  615 + //
  616 + StringBuffer content = new StringBuffer(200);
  617 + content.append("v=0\r\n");
  618 + content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  619 + content.append("s=Talk\r\n");
  620 + content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
  621 + content.append("t=0 0\r\n");
  622 +
  623 + content.append("m=audio " + ssrcInfo.getPort() + " RTP/AVP 8\r\n");
  624 + content.append("a=sendrecv\r\n");
  625 + content.append("a=rtpmap:8 PCMA/8000\r\n");
  626 +
  627 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  628 + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
  629 + content.append("f=v/////a/1/8/1" + "\r\n");
  630 +
  631 + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(), callIdHeader);
  632 + transmitRequest(device.getTransport(), request, (e -> {
  633 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  634 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  635 + errorEvent.response(e);
  636 + }), e -> {
  637 + // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
  638 + ResponseEvent responseEvent = (ResponseEvent) e.event;
  639 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  640 + streamSession.put(device.getDeviceId(), channelId, "talk", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play);
  641 + okEvent.response(e);
  642 + });
  643 + }
  644 +
594 /** 645 /**
595 * 视频流停止, 不使用回调 646 * 视频流停止, 不使用回调
596 */ 647 */
597 @Override 648 @Override
598 - public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException { 649 + public synchronized void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException {
599 streamByeCmd(device, channelId, stream, callId, null); 650 streamByeCmd(device, channelId, stream, callId, null);
600 } 651 }
601 652
@@ -603,7 +654,7 @@ public class SIPCommander implements ISIPCommander { @@ -603,7 +654,7 @@ public class SIPCommander implements ISIPCommander {
603 * 视频流停止 654 * 视频流停止
604 */ 655 */
605 @Override 656 @Override
606 - public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { 657 + public synchronized void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
607 SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream); 658 SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream);
608 if (ssrcTransaction == null) { 659 if (ssrcTransaction == null) {
609 throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream); 660 throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream);
@@ -617,67 +668,34 @@ public class SIPCommander implements ISIPCommander { @@ -617,67 +668,34 @@ public class SIPCommander implements ISIPCommander {
617 transmitRequest(device.getTransport(), byteRequest, null, okEvent); 668 transmitRequest(device.getTransport(), byteRequest, null, okEvent);
618 } 669 }
619 670
620 - /** 671 + @Override
  672 + public synchronized void streamByeCmd(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
  673 + Request byteRequest = headerProvider.createByteRequest(device, channelId, sipTransactionInfo);
  674 + transmitRequest(device.getTransport(), byteRequest, null, okEvent);
  675 + }
  676 +
  677 + /**
621 * 语音广播 678 * 语音广播
622 * 679 *
623 * @param device 视频设备 680 * @param device 视频设备
624 */ 681 */
625 - @Override  
626 - public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException {  
627 -  
628 - StringBuffer broadcastXml = new StringBuffer(200);  
629 - String charset = device.getCharset();  
630 - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
631 - broadcastXml.append("<Notify>\r\n");  
632 - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");  
633 - broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
634 - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");  
635 - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");  
636 - broadcastXml.append("</Notify>\r\n");  
637 - /**  
638 - * 语音广播  
639 - *  
640 - * @param device 视频设备  
641 - */  
642 @Override 682 @Override
643 - public boolean audioBroadcastCmd(Device device,String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {  
644 - try {  
645 - StringBuffer broadcastXml = new StringBuffer(200);  
646 - String charset = device.getCharset();  
647 - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
648 - broadcastXml.append("<Notify>\r\n");  
649 - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");  
650 - broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");  
651 - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");  
652 - broadcastXml.append("<TargetID>" + channelId + "</TargetID>\r\n");  
653 - broadcastXml.append("</Notify>\r\n");  
654 -  
655 - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()  
656 - : udpSipProvider.getNewCallId();  
657 -  
658 - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);  
659 - transmitRequest(device.getTransport(), request);  
660 -  
661 - }  
662 -  
663 - @Override  
664 - public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
665 - 683 + public void audioBroadcastCmd(Device device, String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
666 StringBuffer broadcastXml = new StringBuffer(200); 684 StringBuffer broadcastXml = new StringBuffer(200);
667 String charset = device.getCharset(); 685 String charset = device.getCharset();
668 broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); 686 broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
669 broadcastXml.append("<Notify>\r\n"); 687 broadcastXml.append("<Notify>\r\n");
670 broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n"); 688 broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
671 - broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n"); 689 + broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
672 broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n"); 690 broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
673 - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n"); 691 + broadcastXml.append("<TargetID>" + channelId + "</TargetID>\r\n");
674 broadcastXml.append("</Notify>\r\n"); 692 broadcastXml.append("</Notify>\r\n");
675 693
676 CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() 694 CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
677 : udpSipProvider.getNewCallId(); 695 : udpSipProvider.getNewCallId();
678 696
679 Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader); 697 Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, callIdHeader);
680 - transmitRequest(device.getTransport(), request, errorEvent); 698 + transmitRequest(device.getTransport(), request, errorEvent, okEvent);
681 699
682 } 700 }
683 701
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -676,7 +676,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -676,7 +676,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
676 } 676 }
677 677
678 @Override 678 @Override
679 - public void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException { 679 + public synchronized void streamByeCmd(ParentPlatform platform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException {
680 if (sendRtpItem == null ) { 680 if (sendRtpItem == null ) {
681 logger.info("[向上级发送BYE], sendRtpItem 为NULL"); 681 logger.info("[向上级发送BYE], sendRtpItem 为NULL");
682 return; 682 return;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request;
2 2
  3 +import com.genersoft.iot.vmp.conf.SipConfig;
3 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
4 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 5 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
5 import gov.nist.javax.sip.SipProviderImpl; 6 import gov.nist.javax.sip.SipProviderImpl;
6 import gov.nist.javax.sip.SipStackImpl; 7 import gov.nist.javax.sip.SipStackImpl;
7 import gov.nist.javax.sip.message.SIPRequest; 8 import gov.nist.javax.sip.message.SIPRequest;
8 import gov.nist.javax.sip.message.SIPResponse; 9 import gov.nist.javax.sip.message.SIPResponse;
9 -import gov.nist.javax.sip.stack.SIPServerTransaction;  
10 import gov.nist.javax.sip.stack.SIPServerTransactionImpl; 10 import gov.nist.javax.sip.stack.SIPServerTransactionImpl;
11 import org.apache.commons.lang3.ArrayUtils; 11 import org.apache.commons.lang3.ArrayUtils;
12 import org.dom4j.Document; 12 import org.dom4j.Document;
@@ -27,8 +27,6 @@ import javax.sip.message.MessageFactory; @@ -27,8 +27,6 @@ import javax.sip.message.MessageFactory;
27 import javax.sip.message.Request; 27 import javax.sip.message.Request;
28 import javax.sip.message.Response; 28 import javax.sip.message.Response;
29 import java.io.ByteArrayInputStream; 29 import java.io.ByteArrayInputStream;
30 -import java.nio.ByteBuffer;  
31 -import java.nio.charset.StandardCharsets;  
32 import java.text.ParseException; 30 import java.text.ParseException;
33 import java.util.ArrayList; 31 import java.util.ArrayList;
34 import java.util.Arrays; 32 import java.util.Arrays;
@@ -51,6 +49,9 @@ public abstract class SIPRequestProcessorParent { @@ -51,6 +49,9 @@ public abstract class SIPRequestProcessorParent {
51 @Qualifier(value="udpSipProvider") 49 @Qualifier(value="udpSipProvider")
52 private SipProviderImpl udpSipProvider; 50 private SipProviderImpl udpSipProvider;
53 51
  52 + @Autowired
  53 + private SipConfig sipConfig;
  54 +
54 /** 55 /**
55 * 根据 RequestEvent 获取 ServerTransaction 56 * 根据 RequestEvent 获取 ServerTransaction
56 * @param evt 57 * @param evt
@@ -60,13 +61,15 @@ public abstract class SIPRequestProcessorParent { @@ -60,13 +61,15 @@ public abstract class SIPRequestProcessorParent {
60 Request request = evt.getRequest(); 61 Request request = evt.getRequest();
61 SIPServerTransactionImpl serverTransaction = (SIPServerTransactionImpl)evt.getServerTransaction(); 62 SIPServerTransactionImpl serverTransaction = (SIPServerTransactionImpl)evt.getServerTransaction();
62 // 判断TCP还是UDP 63 // 判断TCP还是UDP
  64 + boolean isTcp = false;
63 ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); 65 ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
64 String transport = reqViaHeader.getTransport(); 66 String transport = reqViaHeader.getTransport();
  67 + if (transport.equalsIgnoreCase("TCP")) {
  68 + isTcp = true;
  69 + }
65 if (serverTransaction != null && serverTransaction.getOriginalRequest() == null) { 70 if (serverTransaction != null && serverTransaction.getOriginalRequest() == null) {
66 serverTransaction.setOriginalRequest((SIPRequest) evt.getRequest()); 71 serverTransaction.setOriginalRequest((SIPRequest) evt.getRequest());
67 } 72 }
68 - boolean isTcp = "TCP".equals(transport);  
69 -  
70 if (serverTransaction == null) { 73 if (serverTransaction == null) {
71 try { 74 try {
72 if (isTcp) { 75 if (isTcp) {
@@ -187,7 +190,6 @@ public abstract class SIPRequestProcessorParent { @@ -187,7 +190,6 @@ public abstract class SIPRequestProcessorParent {
187 * 回复带sdp的200 190 * 回复带sdp的200
188 */ 191 */
189 public SIPResponse responseSdpAck(ServerTransaction serverTransaction, String sdp, ParentPlatform platform) throws SipException, InvalidArgumentException, ParseException { 192 public SIPResponse responseSdpAck(ServerTransaction serverTransaction, String sdp, ParentPlatform platform) throws SipException, InvalidArgumentException, ParseException {
190 -  
191 ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); 193 ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
192 194
193 // 兼容国标中的使用编码@域名作为RequestURI的情况 195 // 兼容国标中的使用编码@域名作为RequestURI的情况
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; @@ -2,6 +2,7 @@ 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.exception.SsrcTransactionNotFoundException;
5 import com.genersoft.iot.vmp.gb28181.bean.*; 6 import com.genersoft.iot.vmp.gb28181.bean.*;
6 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; 7 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
7 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 8 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
@@ -14,6 +15,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP @@ -14,6 +15,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP
14 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 15 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
15 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 16 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
16 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 17 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  18 +import com.genersoft.iot.vmp.service.IDeviceService;
17 import com.genersoft.iot.vmp.service.IMediaServerService; 19 import com.genersoft.iot.vmp.service.IMediaServerService;
18 import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; 20 import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
19 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; 21 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
@@ -21,7 +23,6 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -21,7 +23,6 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
21 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 23 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
22 import gov.nist.javax.sip.message.SIPRequest; 24 import gov.nist.javax.sip.message.SIPRequest;
23 import gov.nist.javax.sip.stack.SIPDialog; 25 import gov.nist.javax.sip.stack.SIPDialog;
24 -import com.genersoft.iot.vmp.utils.SerializeUtils;  
25 import org.slf4j.Logger; 26 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory; 27 import org.slf4j.LoggerFactory;
27 import org.springframework.beans.factory.InitializingBean; 28 import org.springframework.beans.factory.InitializingBean;
@@ -82,6 +83,9 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -82,6 +83,9 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
82 private ISIPCommander cmder; 83 private ISIPCommander cmder;
83 84
84 @Autowired 85 @Autowired
  86 + private IDeviceService deviceService;
  87 +
  88 + @Autowired
85 private ISIPCommanderForPlatform commanderForPlatform; 89 private ISIPCommanderForPlatform commanderForPlatform;
86 90
87 @Autowired 91 @Autowired
@@ -106,7 +110,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -106,7 +110,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
106 // 取消设置的超时任务 110 // 取消设置的超时任务
107 dynamicTask.stop(callIdHeader.getCallId()); 111 dynamicTask.stop(callIdHeader.getCallId());
108 String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser(); 112 String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
109 - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId, null, callIdHeader.getCallId()); 113 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
110 if (sendRtpItem == null) { 114 if (sendRtpItem == null) {
111 logger.warn("[收到ACK]:未找到通道({})的推流信息", channelId); 115 logger.warn("[收到ACK]:未找到通道({})的推流信息", channelId);
112 return; 116 return;
@@ -123,7 +127,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -123,7 +127,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
123 param.put("pt", sendRtpItem.getPt()); 127 param.put("pt", sendRtpItem.getPt());
124 param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0"); 128 param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
125 param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0"); 129 param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
126 - if (!sendRtpItem.isTcp() && parentPlatform.isRtcp()) { 130 + if (!sendRtpItem.isTcp() && parentPlatform != null && parentPlatform.isRtcp()) {
127 // 开启rtcp保活 131 // 开启rtcp保活
128 param.put("udp_rtcp_timeout", "1"); 132 param.put("udp_rtcp_timeout", "1");
129 } 133 }
@@ -141,29 +145,28 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -141,29 +145,28 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
141 if (jsonObject == null) { 145 if (jsonObject == null) {
142 logger.error("RTP推流失败: 请检查ZLM服务"); 146 logger.error("RTP推流失败: 请检查ZLM服务");
143 } else if (jsonObject.getInteger("code") == 0) { 147 } else if (jsonObject.getInteger("code") == 0) {
144 -  
145 - if (sendRtpItem.isOnlyAudio()) {  
146 - AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());  
147 - audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.Ok);  
148 - audioBroadcastCatch.setDialog((SIPDialog) evt.getDialog());  
149 - audioBroadcastCatch.setRequest((SIPRequest) evt.getRequest());  
150 - audioBroadcastManager.update(audioBroadcastCatch);  
151 - String waiteStreamTimeoutTaskKey = "waite-stream-" + audioBroadcastCatch.getDeviceId() + audioBroadcastCatch.getChannelId();  
152 - dynamicTask.stop(waiteStreamTimeoutTaskKey);  
153 - }  
154 logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port")); 148 logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
155 } else { 149 } else {
156 logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSONObject.toJSON(param)); 150 logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSONObject.toJSON(param));
157 if (sendRtpItem.isOnlyAudio()) { 151 if (sendRtpItem.isOnlyAudio()) {
158 // 语音对讲 152 // 语音对讲
159 - try {  
160 - cmder.streamByeCmd((SIPDialog) evt.getDialog(), sendRtpItem.getChannelId(), (SIPRequest) evt.getRequest(), null);  
161 - } catch (SipException | ParseException | InvalidArgumentException e) {  
162 - logger.error("[命令发送失败] 停止语音对讲: {}", e.getMessage()); 153 + Device device = deviceService.queryDevice(platformGbId);
  154 + if (device != null) {
  155 + try {
  156 + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), sendRtpItem.getStreamId(), null);
  157 + } catch (SipException | ParseException | InvalidArgumentException |
  158 + SsrcTransactionNotFoundException e) {
  159 + logger.error("[命令发送失败] 停止语音对讲: {}", e.getMessage());
  160 + }
163 } 161 }
  162 +
164 } else { 163 } else {
165 // 向上级平台 164 // 向上级平台
166 - commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId()); 165 + try {
  166 + commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
  167 + } catch (SipException | InvalidArgumentException | ParseException e) {
  168 + logger.error("[命令发送失败] 国标级联, 回复BYE: {}", e.getMessage());
  169 + }
167 } 170 }
168 if (mediaInfo == null) { 171 if (mediaInfo == null) {
169 RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance( 172 RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
@@ -179,7 +182,6 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -179,7 +182,6 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
179 } 182 }
180 183
181 184
182 - }  
183 } 185 }
184 } 186 }
185 private void startSendRtpStreamHand(RequestEvent evt, SendRtpItem sendRtpItem, ParentPlatform parentPlatform, 187 private void startSendRtpStreamHand(RequestEvent evt, SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
@@ -2,10 +2,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; @@ -2,10 +2,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2
3 import com.genersoft.iot.vmp.common.StreamInfo; 3 import com.genersoft.iot.vmp.common.StreamInfo;
4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
6 -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType;  
7 -import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;  
8 -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; 5 +import com.genersoft.iot.vmp.gb28181.bean.*;
  6 +import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
9 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 7 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
10 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 8 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 9 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
@@ -55,6 +53,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -55,6 +53,9 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
55 private IDeviceService deviceService; 53 private IDeviceService deviceService;
56 54
57 @Autowired 55 @Autowired
  56 + private AudioBroadcastManager audioBroadcastManager;
  57 +
  58 + @Autowired
58 private IVideoManagerStorage storager; 59 private IVideoManagerStorage storager;
59 60
60 @Autowired 61 @Autowired
@@ -91,78 +92,79 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -91,78 +92,79 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
91 logger.error("[回复BYE信息失败],{}", e.getMessage()); 92 logger.error("[回复BYE信息失败],{}", e.getMessage());
92 } 93 }
93 CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); 94 CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
94 - String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();  
95 - String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();  
96 - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId, null, callIdHeader.getCallId());  
97 - logger.info("[收到bye] {}/{}", platformGbId, channelId);  
98 - if (sendRtpItem != null){  
99 - String streamId = sendRtpItem.getStreamId();  
100 - Map<String, Object> param = new HashMap<>();  
101 - param.put("vhost","__defaultVhost__");  
102 - param.put("app",sendRtpItem.getApp());  
103 - param.put("stream",streamId);  
104 - param.put("ssrc",sendRtpItem.getSsrc());  
105 - logger.info("[收到bye] 停止向上级推流:{}", streamId);  
106 - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());  
107 - redisCatchStorage.deleteSendRTPServer(platformGbId, channelId, callIdHeader.getCallId(), null);  
108 - zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);  
109 - int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);  
110 - if (totalReaderCount <= 0) {  
111 - logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId);  
112 - if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) {  
113 - Device device = deviceService.queryDevice(sendRtpItem.getDeviceId());  
114 - if (device == null) {  
115 - logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId);  
116 - }  
117 - try {  
118 - logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), channelId);  
119 - cmder.streamByeCmd(device, channelId, streamId, null);  
120 - } catch (InvalidArgumentException | ParseException | SipException |  
121 - SsrcTransactionNotFoundException e) {  
122 - logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage());  
123 - } 95 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
  96 +
  97 + if (sendRtpItem != null){
  98 + logger.info("[收到bye] {}/{}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId());
  99 + String streamId = sendRtpItem.getStreamId();
  100 + Map<String, Object> param = new HashMap<>();
  101 + param.put("vhost","__defaultVhost__");
  102 + param.put("app",sendRtpItem.getApp());
  103 + param.put("stream",streamId);
  104 + param.put("ssrc",sendRtpItem.getSsrc());
  105 + logger.info("[收到bye] 停止向上级推流:{}", streamId);
  106 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  107 + redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), callIdHeader.getCallId(), null);
  108 + zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
  109 + int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);
  110 + if (totalReaderCount <= 0) {
  111 + logger.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId);
  112 + if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) {
  113 + Device device = deviceService.queryDevice(sendRtpItem.getDeviceId());
  114 + if (device == null) {
  115 + logger.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId);
124 } 116 }
125 - if (sendRtpItem.isOnlyAudio()) {  
126 - playService.stopAudioBroadcast(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); 117 + try {
  118 + logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
  119 + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null);
  120 + } catch (InvalidArgumentException | ParseException | SipException |
  121 + SsrcTransactionNotFoundException e) {
  122 + logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage());
127 } 123 }
128 - if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {  
129 - MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,  
130 - sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(),  
131 - sendRtpItem.getPlatformId(), null, null, sendRtpItem.getMediaServerId());  
132 - redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);  
133 - }  
134 - }  
135 - }  
136 - // 可能是设备主动停止  
137 - Device device = storager.queryVideoDeviceByChannelId(platformGbId);  
138 - if (device != null) {  
139 - storager.stopPlay(device.getDeviceId(), channelId);  
140 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);  
141 - if (streamInfo != null) {  
142 - redisCatchStorage.stopPlay(streamInfo);  
143 - mediaServerService.closeRTPServer(streamInfo.getMediaServerId(), streamInfo.getStream());  
144 } 124 }
145 - SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);  
146 - if (ssrcTransactionForPlay != null){  
147 - if (ssrcTransactionForPlay.getCallId().equals(callIdHeader.getCallId())){  
148 - // 释放ssrc  
149 - MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlay.getMediaServerId());  
150 - if (mediaServerItem != null) {  
151 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlay.getSsrc());  
152 - }  
153 - streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream());  
154 - } 125 +
  126 + if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {
  127 + MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
  128 + sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(),
  129 + sendRtpItem.getPlatformId(), null, null, sendRtpItem.getMediaServerId());
  130 + redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);
155 } 131 }
156 - SsrcTransaction ssrcTransactionForPlayBack = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callIdHeader.getCallId(), null);  
157 - if (ssrcTransactionForPlayBack != null) { 132 + }
  133 + playService.stopAudioBroadcast(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
  134 + }
  135 +
  136 + String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
  137 + String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
  138 +
  139 + // 可能是设备主动停止
  140 + Device device = storager.queryVideoDeviceByChannelId(platformGbId);
  141 + if (device != null) {
  142 + storager.stopPlay(device.getDeviceId(), channelId);
  143 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
  144 + if (streamInfo != null) {
  145 + redisCatchStorage.stopPlay(streamInfo);
  146 + mediaServerService.closeRTPServer(streamInfo.getMediaServerId(), streamInfo.getStream());
  147 + }
  148 + SsrcTransaction ssrcTransactionForPlay = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, "play", null);
  149 + if (ssrcTransactionForPlay != null){
  150 + if (ssrcTransactionForPlay.getCallId().equals(callIdHeader.getCallId())){
158 // 释放ssrc 151 // 释放ssrc
159 - MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlayBack.getMediaServerId()); 152 + MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlay.getMediaServerId());
160 if (mediaServerItem != null) { 153 if (mediaServerItem != null) {
161 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlayBack.getSsrc()); 154 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlay.getSsrc());
162 } 155 }
163 - streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlayBack.getStream()); 156 + streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream());
164 } 157 }
165 } 158 }
166 - 159 + SsrcTransaction ssrcTransactionForPlayBack = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callIdHeader.getCallId(), null);
  160 + if (ssrcTransactionForPlayBack != null) {
  161 + // 释放ssrc
  162 + MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransactionForPlayBack.getMediaServerId());
  163 + if (mediaServerItem != null) {
  164 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransactionForPlayBack.getSsrc());
  165 + }
  166 + streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlayBack.getStream());
  167 + }
  168 + }
167 } 169 }
168 } 170 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2
3 -import com.alibaba.fastjson.JSON;  
4 -import com.alibaba.fastjson.JSONArray;  
5 import com.alibaba.fastjson.JSONObject; 3 import com.alibaba.fastjson.JSONObject;
6 import com.genersoft.iot.vmp.conf.DynamicTask; 4 import com.genersoft.iot.vmp.conf.DynamicTask;
7 import com.genersoft.iot.vmp.conf.SipConfig; 5 import com.genersoft.iot.vmp.conf.SipConfig;
8 import com.genersoft.iot.vmp.conf.UserSetting; 6 import com.genersoft.iot.vmp.conf.UserSetting;
  7 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
9 import com.genersoft.iot.vmp.gb28181.bean.*; 8 import com.genersoft.iot.vmp.gb28181.bean.*;
10 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 9 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
11 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; 10 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
@@ -14,7 +13,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; @@ -14,7 +13,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
14 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 13 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
15 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 14 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
16 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 15 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
17 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 16 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
  17 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
18 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; 18 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
19 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 19 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
20 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 20 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
@@ -30,20 +30,16 @@ import com.genersoft.iot.vmp.service.IStreamProxyService; @@ -30,20 +30,16 @@ import com.genersoft.iot.vmp.service.IStreamProxyService;
30 import com.genersoft.iot.vmp.service.IStreamPushService; 30 import com.genersoft.iot.vmp.service.IStreamPushService;
31 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 31 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
32 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 32 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
33 -import com.genersoft.iot.vmp.service.impl.RedisGbPlayMsgListener;  
34 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; 33 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
35 import com.genersoft.iot.vmp.service.redisMsg.RedisPushStreamResponseListener; 34 import com.genersoft.iot.vmp.service.redisMsg.RedisPushStreamResponseListener;
36 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 35 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
37 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 36 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
38 import com.genersoft.iot.vmp.utils.DateUtil; 37 import com.genersoft.iot.vmp.utils.DateUtil;
39 -import com.genersoft.iot.vmp.utils.SerializeUtils;  
40 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; 38 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
41 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 39 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
42 import gov.nist.javax.sdp.TimeDescriptionImpl; 40 import gov.nist.javax.sdp.TimeDescriptionImpl;
43 import gov.nist.javax.sdp.fields.TimeField; 41 import gov.nist.javax.sdp.fields.TimeField;
44 import gov.nist.javax.sip.message.SIPRequest; 42 import gov.nist.javax.sip.message.SIPRequest;
45 -import gov.nist.javax.sip.stack.SIPDialog;  
46 -import gov.nist.javax.sip.message.SIPRequest;  
47 import gov.nist.javax.sip.message.SIPResponse; 43 import gov.nist.javax.sip.message.SIPResponse;
48 import org.slf4j.Logger; 44 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory; 45 import org.slf4j.LoggerFactory;
@@ -72,7 +68,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -72,7 +68,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
72 private final String method = "INVITE"; 68 private final String method = "INVITE";
73 69
74 @Autowired 70 @Autowired
75 - private SIPCommanderFroPlatform cmderFroPlatform; 71 + private ISIPCommanderForPlatform cmderFroPlatform;
76 72
77 @Autowired 73 @Autowired
78 private IVideoManagerStorage storager; 74 private IVideoManagerStorage storager;
@@ -174,7 +170,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -174,7 +170,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
174 // 查询请求是否来自上级平台\设备 170 // 查询请求是否来自上级平台\设备
175 ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId); 171 ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
176 if (platform == null) { 172 if (platform == null) {
177 - inviteFromDeviceHandle(serverTransaction, requesterId); 173 + inviteFromDeviceHandle(serverTransaction, requesterId, channelId);
178 } else { 174 } else {
179 // 查询平台下是否有该通道 175 // 查询平台下是否有该通道
180 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); 176 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
@@ -393,14 +389,15 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -393,14 +389,15 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
393 }; 389 };
394 SipSubscribe.Event errorEvent = ((event) -> { 390 SipSubscribe.Event errorEvent = ((event) -> {
395 // 未知错误。直接转发设备点播的错误 391 // 未知错误。直接转发设备点播的错误
396 - Response response = null;  
397 try { 392 try {
398 - response = getMessageFactory().createResponse(event.statusCode, evt.getRequest()); 393 + Response response = getMessageFactory().createResponse(event.statusCode, evt.getRequest());
399 serverTransaction.sendResponse(response); 394 serverTransaction.sendResponse(response);
400 System.out.println("未知错误。直接转发设备点播的错误"); 395 System.out.println("未知错误。直接转发设备点播的错误");
401 if (serverTransaction.getDialog() != null) { 396 if (serverTransaction.getDialog() != null) {
402 serverTransaction.getDialog().delete(); 397 serverTransaction.getDialog().delete();
403 } 398 }
  399 + serverTransaction.getDialog().delete();
  400 +
404 } catch (ParseException | SipException | InvalidArgumentException e) { 401 } catch (ParseException | SipException | InvalidArgumentException e) {
405 e.printStackTrace(); 402 e.printStackTrace();
406 } 403 }
@@ -817,7 +814,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -817,7 +814,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
817 } 814 }
818 815
819 public void inviteFromDeviceHandle(ServerTransaction serverTransaction, String requesterId, String channelId) throws InvalidArgumentException, ParseException, SipException, SdpException { 816 public void inviteFromDeviceHandle(ServerTransaction serverTransaction, String requesterId, String channelId) throws InvalidArgumentException, ParseException, SipException, SdpException {
820 -  
821 // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备) 817 // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
822 Device device = redisCatchStorage.getDevice(requesterId); 818 Device device = redisCatchStorage.getDevice(requesterId);
823 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(requesterId, channelId); 819 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(requesterId, channelId);
@@ -918,125 +914,64 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -918,125 +914,64 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
918 sendRtpItem.setOnlyAudio(true); 914 sendRtpItem.setOnlyAudio(true);
919 redisCatchStorage.updateSendRTPSever(sendRtpItem); 915 redisCatchStorage.updateSendRTPSever(sendRtpItem);
920 916
921 - // hook监听等待设备推流上来  
922 - // 添加订阅  
923 - HookSubscribeForStreamChange subscribeKey = HookSubscribeFactory.on_stream_changed(app, stream, true, "rtsp", mediaServerItem.getId());  
924 -  
925 - String finalSsrc = ssrc;  
926 - // 流已经存在时直接推流  
927 - // 设置等待推流的超时; 默认20s  
928 - String waiteStreamTimeoutTaskKey = "waite-stream-" + device.getDeviceId() + audioBroadcastCatch.getChannelId();  
929 - dynamicTask.startDelay(waiteStreamTimeoutTaskKey, ()->{  
930 - logger.info("等待推流超时: {}/{}", app, stream);  
931 - subscribe.removeSubscribe(subscribeKey);  
932 - playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());  
933 - // 发送bye  
934 - try {  
935 - responseAck(evt, Response.BUSY_HERE);  
936 - } catch (SipException e) {  
937 - throw new RuntimeException(e);  
938 - } catch (InvalidArgumentException e) {  
939 - throw new RuntimeException(e);  
940 - } catch (ParseException e) {  
941 - throw new RuntimeException(e);  
942 - }  
943 - }, 20*1000);  
944 -  
945 - boolean finalMediaTransmissionTCP = mediaTransmissionTCP;  
946 - subscribe.addSubscribe(subscribeKey,  
947 - (MediaServerItem mediaServerItemInUse, JSONObject json)->{  
948 - logger.info("收到语音对讲推流");  
949 - dynamicTask.stop(waiteStreamTimeoutTaskKey);  
950 - MediaItem mediaItem = JSON.toJavaObject(json, MediaItem.class);  
951 - Integer audioCodecId = null;  
952 - if (mediaItem.getTracks() != null && mediaItem.getTracks().size() > 0) {  
953 - for (int i = 0; i < mediaItem.getTracks().size(); i++) {  
954 - MediaItem.MediaTrack mediaTrack = mediaItem.getTracks().get(i);  
955 - if (mediaTrack.getCodecType() == 1) {  
956 - audioCodecId = mediaTrack.getCodecId();  
957 - break;  
958 - }  
959 - }  
960 - }  
961 -  
962 - try {  
963 - sendRtpItem.setStatus(2);  
964 - redisCatchStorage.updateSendRTPSever(sendRtpItem);  
965 - StringBuffer content = new StringBuffer(200);  
966 - content.append("v=0\r\n");  
967 - content.append("o="+ config.getId() +" "+ sdp.getOrigin().getSessionId() +" " + sdp.getOrigin().getSessionVersion() + " IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");  
968 - content.append("s=Play\r\n");  
969 - content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");  
970 - content.append("t=0 0\r\n");  
971 - if (audioCodecId == null) {  
972 - if (finalMediaTransmissionTCP) {  
973 - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");  
974 - }else {  
975 - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");  
976 - }  
977 -  
978 - content.append("a=rtpmap:8 PCMA/8000\r\n");  
979 - }else {  
980 - if (audioCodecId == 4) {  
981 - if (finalMediaTransmissionTCP) {  
982 - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 0\r\n");  
983 - }else {  
984 - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 0\r\n");  
985 - }  
986 - content.append("a=rtpmap:0 PCMU/8000\r\n");  
987 - }else {  
988 - if (finalMediaTransmissionTCP) {  
989 - content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");  
990 - }else {  
991 - content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");  
992 - }  
993 - content.append("a=rtpmap:8 PCMA/8000\r\n");  
994 - }  
995 - }  
996 - content.append("a=sendonly\r\n");  
997 - if (sendRtpItem.isTcp()) {  
998 - content.append("a=connection:new\r\n");  
999 - if (!sendRtpItem.isTcpActive()) {  
1000 - content.append("a=setup:active\r\n");  
1001 - }else {  
1002 - content.append("a=setup:passive\r\n");  
1003 - }  
1004 - }  
1005 - content.append("y="+ finalSsrc + "\r\n");  
1006 - content.append("f=v/////a/1/8/1\r\n");  
1007 -  
1008 - ParentPlatform parentPlatform = new ParentPlatform();  
1009 - parentPlatform.setServerIP(device.getIp());  
1010 - parentPlatform.setServerPort(device.getPort());  
1011 - parentPlatform.setServerGBId(device.getDeviceId());  
1012 -  
1013 - responseSdpAck(serverTransaction, content.toString(), parentPlatform);  
1014 - Dialog dialog = evt.getDialog();  
1015 - audioBroadcastCatch.setDialog((SIPDialog) dialog);  
1016 - audioBroadcastCatch.setRequest((SIPRequest) request);  
1017 - audioBroadcastManager.update(audioBroadcastCatch);  
1018 - } catch (SipException | InvalidArgumentException | ParseException | SdpParseException e) {  
1019 - logger.error("[命令发送失败] 语音对讲: {}", e.getMessage());  
1020 - }  
1021 - });  
1022 -// }  
1023 - String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId();  
1024 - WVPResult<AudioBroadcastResult> wvpResult = new WVPResult<>();  
1025 - wvpResult.setCode(0);  
1026 - wvpResult.setMsg("success");  
1027 - AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult();  
1028 - audioBroadcastResult.setApp(app);  
1029 - audioBroadcastResult.setStream(stream);  
1030 - audioBroadcastResult.setStreamInfo(mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, stream, null, null, null,false));  
1031 - audioBroadcastResult.setCodec("G.711");  
1032 - wvpResult.setData(audioBroadcastResult);  
1033 - RequestMessage requestMessage = new RequestMessage();  
1034 - requestMessage.setKey(key);  
1035 - requestMessage.setData(wvpResult);  
1036 - resultHolder.invokeAllResult(requestMessage); 917 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream);
  918 + if (streamReady) {
  919 + sendOk(device, sendRtpItem, sdp, serverTransaction, mediaServerItem, mediaTransmissionTCP, ssrc);
  920 + }else {
  921 + logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", app, stream);
  922 + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  923 + }
1037 } else { 924 } else {
1038 logger.warn("来自无效设备/平台的请求"); 925 logger.warn("来自无效设备/平台的请求");
1039 responseAck(serverTransaction, Response.BAD_REQUEST); 926 responseAck(serverTransaction, Response.BAD_REQUEST);
1040 } 927 }
1041 } 928 }
  929 +
  930 + void sendOk(Device device, SendRtpItem sendRtpItem, SessionDescription sdp, ServerTransaction serverTransaction, MediaServerItem mediaServerItem, boolean mediaTransmissionTCP, String ssrc){
  931 + try {
  932 + sendRtpItem.setStatus(2);
  933 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  934 + StringBuffer content = new StringBuffer(200);
  935 + content.append("v=0\r\n");
  936 + content.append("o="+ config.getId() +" "+ sdp.getOrigin().getSessionId() +" " + sdp.getOrigin().getSessionVersion() + " IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  937 + content.append("s=Play\r\n");
  938 + content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
  939 + content.append("t=0 0\r\n");
  940 +
  941 + if (mediaTransmissionTCP) {
  942 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" TCP/RTP/AVP 8\r\n");
  943 + }else {
  944 + content.append("m=audio "+ sendRtpItem.getLocalPort()+" RTP/AVP 8\r\n");
  945 + }
  946 +
  947 + content.append("a=rtpmap:8 PCMA/8000/1\r\n");
  948 +
  949 + content.append("a=sendonly\r\n");
  950 + if (sendRtpItem.isTcp()) {
  951 + content.append("a=connection:new\r\n");
  952 + if (!sendRtpItem.isTcpActive()) {
  953 + content.append("a=setup:active\r\n");
  954 + }else {
  955 + content.append("a=setup:passive\r\n");
  956 + }
  957 + }
  958 + content.append("y="+ ssrc + "\r\n");
  959 + content.append("f=v/////a/1/8/1\r\n");
  960 +
  961 + ParentPlatform parentPlatform = new ParentPlatform();
  962 + parentPlatform.setServerIP(device.getIp());
  963 + parentPlatform.setServerPort(device.getPort());
  964 + parentPlatform.setServerGBId(device.getDeviceId());
  965 +
  966 + SIPResponse sipResponse = responseSdpAck(serverTransaction, content.toString(), parentPlatform);
  967 +
  968 + AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), sendRtpItem.getChannelId());
  969 +
  970 + audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.Ok);
  971 + audioBroadcastCatch.setSipTransactionInfoByRequset(sipResponse);
  972 + audioBroadcastManager.update(audioBroadcastCatch);
  973 + } catch (SipException | InvalidArgumentException | ParseException | SdpParseException e) {
  974 + logger.error("[命令发送失败] 语音对讲 回复200OK(SDP): {}", e.getMessage());
  975 + }
  976 + }
1042 } 977 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -20,12 +20,8 @@ import org.springframework.beans.factory.InitializingBean; @@ -20,12 +20,8 @@ import org.springframework.beans.factory.InitializingBean;
20 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
21 import org.springframework.stereotype.Component; 21 import org.springframework.stereotype.Component;
22 import org.springframework.util.ObjectUtils; 22 import org.springframework.util.ObjectUtils;
23 -import org.springframework.util.StringUtils;  
24 23
25 -import javax.sip.InvalidArgumentException;  
26 -import javax.sip.RequestEvent;  
27 -import javax.sip.ServerTransaction;  
28 -import javax.sip.SipException; 24 +import javax.sip.*;
29 import javax.sip.header.*; 25 import javax.sip.header.*;
30 import javax.sip.message.Request; 26 import javax.sip.message.Request;
31 import javax.sip.message.Response; 27 import javax.sip.message.Response;
@@ -116,10 +112,12 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -116,10 +112,12 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
116 112
117 if (expiresHeader == null) { 113 if (expiresHeader == null) {
118 response = getMessageFactory().createResponse(Response.BAD_REQUEST, request); 114 response = getMessageFactory().createResponse(Response.BAD_REQUEST, request);
119 - ServerTransaction serverTransaction = getServerTransaction(evt);  
120 - serverTransaction.sendResponse(response);  
121 - if (serverTransaction.getDialog() != null) {  
122 - serverTransaction.getDialog().delete(); 115 + if (evt.getDialog() != null ) {
  116 + if (evt.getDialog().isServer()) {
  117 + ServerTransaction serverTransaction = getServerTransaction(evt);
  118 + serverTransaction.sendResponse(response);
  119 + serverTransaction.getDialog().delete();
  120 + }
123 } 121 }
124 return; 122 return;
125 } 123 }
@@ -176,19 +174,13 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -176,19 +174,13 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
176 } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) { 174 } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
177 e.printStackTrace(); 175 e.printStackTrace();
178 } 176 }
179 -  
180 } 177 }
181 178
182 private void sendResponse(RequestEvent evt, Response response) throws InvalidArgumentException, SipException { 179 private void sendResponse(RequestEvent evt, Response response) throws InvalidArgumentException, SipException {
183 ServerTransaction serverTransaction = getServerTransaction(evt); 180 ServerTransaction serverTransaction = getServerTransaction(evt);
184 - if (serverTransaction == null) {  
185 - logger.warn("[回复失败]:{}", response);  
186 - return;  
187 - }  
188 serverTransaction.sendResponse(response); 181 serverTransaction.sendResponse(response);
189 if (serverTransaction.getDialog() != null) { 182 if (serverTransaction.getDialog() != null) {
190 serverTransaction.getDialog().delete(); 183 serverTransaction.getDialog().delete();
191 } 184 }
192 } 185 }
193 -  
194 } 186 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2
3 -import com.genersoft.iot.vmp.common.VideoManagerConstants;  
4 import com.genersoft.iot.vmp.conf.DynamicTask; 3 import com.genersoft.iot.vmp.conf.DynamicTask;
5 import com.genersoft.iot.vmp.conf.UserSetting; 4 import com.genersoft.iot.vmp.conf.UserSetting;
6 import com.genersoft.iot.vmp.gb28181.bean.CmdType; 5 import com.genersoft.iot.vmp.gb28181.bean.CmdType;
7 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
8 import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; 7 import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
9 import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; 8 import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
10 -import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask;  
11 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 9 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
12 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;  
13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; 10 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
15 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 12 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
16 import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; 13 import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
17 -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;  
18 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 14 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
19 import gov.nist.javax.sip.SipProviderImpl; 15 import gov.nist.javax.sip.SipProviderImpl;
20 import gov.nist.javax.sip.message.SIPRequest; 16 import gov.nist.javax.sip.message.SIPRequest;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java
@@ -3,11 +3,15 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message; @@ -3,11 +3,15 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
3 import com.genersoft.iot.vmp.gb28181.bean.Device; 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
5 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 5 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
  6 +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.AckRequestProcessor;
6 import org.dom4j.Element; 7 import org.dom4j.Element;
  8 +import org.slf4j.Logger;
  9 +import org.slf4j.LoggerFactory;
7 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.beans.factory.annotation.Autowired;
8 11
9 import javax.sip.InvalidArgumentException; 12 import javax.sip.InvalidArgumentException;
10 import javax.sip.RequestEvent; 13 import javax.sip.RequestEvent;
  14 +import javax.sip.ServerTransaction;
11 import javax.sip.SipException; 15 import javax.sip.SipException;
12 import javax.sip.message.Response; 16 import javax.sip.message.Response;
13 import java.text.ParseException; 17 import java.text.ParseException;
@@ -18,6 +22,8 @@ import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; @@ -18,6 +22,8 @@ import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
18 22
19 public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent implements IMessageHandler{ 23 public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent implements IMessageHandler{
20 24
  25 + private Logger logger = LoggerFactory.getLogger(MessageHandlerAbstract.class);
  26 +
21 public Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>(); 27 public Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
22 28
23 public void addHandler(String cmdType, IMessageHandler messageHandler) { 29 public void addHandler(String cmdType, IMessageHandler messageHandler) {
@@ -48,14 +54,10 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i @@ -48,14 +54,10 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
48 54
49 public void handNullCmd(RequestEvent evt){ 55 public void handNullCmd(RequestEvent evt){
50 try { 56 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); 57 + ServerTransaction serverTransaction = getServerTransaction(evt);
  58 + responseAck(serverTransaction, Response.OK);
  59 + } catch (SipException | InvalidArgumentException | ParseException e) {
  60 + logger.error("[命令发送失败] 回复200 OK: {}", e.getMessage());
58 } 61 }
59 - return;  
60 } 62 }
61 } 63 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
@@ -52,16 +52,17 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i @@ -52,16 +52,17 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i
52 public void handForDevice(RequestEvent evt, Device device, Element rootElement) { 52 public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
53 try { 53 try {
54 String channelId = getText(rootElement, "DeviceID"); 54 String channelId = getText(rootElement, "DeviceID");
  55 + ServerTransaction serverTransaction = getServerTransaction(evt);
55 if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) { 56 if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
56 // 回复410 57 // 回复410
57 - responseAck(evt, Response.GONE); 58 + responseAck(serverTransaction, Response.GONE);
58 return; 59 return;
59 } 60 }
60 logger.info("收到语音广播的回复:{}/{}", device.getDeviceId(), channelId ); 61 logger.info("收到语音广播的回复:{}/{}", device.getDeviceId(), channelId );
61 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), channelId); 62 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), channelId);
62 audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.WaiteInvite); 63 audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.WaiteInvite);
63 audioBroadcastManager.update(audioBroadcastCatch); 64 audioBroadcastManager.update(audioBroadcastCatch);
64 - responseAck(evt, Response.OK); 65 + responseAck(serverTransaction, Response.OK);
65 } catch (ParseException | SipException | InvalidArgumentException e) { 66 } catch (ParseException | SipException | InvalidArgumentException e) {
66 logger.error("[命令发送失败] 国标级联 语音喊话: {}", e.getMessage()); 67 logger.error("[命令发送失败] 国标级联 语音喊话: {}", e.getMessage());
67 } 68 }
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
@@ -113,4 +113,7 @@ public class SipUtils { @@ -113,4 +113,7 @@ public class SipUtils {
113 return builder.toString(); 113 return builder.toString();
114 } 114 }
115 115
  116 + public static String getNewCallId() {
  117 + return (int) Math.floor(Math.random() * 10000) + "";
  118 + }
116 } 119 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -11,12 +11,16 @@ import com.genersoft.iot.vmp.conf.UserSetting; @@ -11,12 +11,16 @@ import com.genersoft.iot.vmp.conf.UserSetting;
11 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 11 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
12 import com.genersoft.iot.vmp.gb28181.bean.*; 12 import com.genersoft.iot.vmp.gb28181.bean.*;
13 import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 13 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
  14 +import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
14 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 15 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
15 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 16 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  17 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
16 import com.genersoft.iot.vmp.media.zlm.dto.*; 18 import com.genersoft.iot.vmp.media.zlm.dto.*;
17 import com.genersoft.iot.vmp.service.*; 19 import com.genersoft.iot.vmp.service.*;
18 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
19 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 21 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  22 +import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
  23 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
20 import org.slf4j.Logger; 24 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory; 25 import org.slf4j.LoggerFactory;
22 import org.springframework.beans.factory.annotation.Autowired; 26 import org.springframework.beans.factory.annotation.Autowired;
@@ -51,7 +55,13 @@ public class ZLMHttpHookListener { @@ -51,7 +55,13 @@ public class ZLMHttpHookListener {
51 private SIPCommander cmder; 55 private SIPCommander cmder;
52 56
53 @Autowired 57 @Autowired
54 - private SIPCommanderFroPlatform commanderFroPlatform; 58 + private ISIPCommanderForPlatform commanderFroPlatform;
  59 +
  60 + @Autowired
  61 + private AudioBroadcastManager audioBroadcastManager;
  62 +
  63 + @Autowired
  64 + private ZLMRTPServerFactory zlmrtpServerFactory;
55 65
56 @Autowired 66 @Autowired
57 private IPlayService playService; 67 private IPlayService playService;
@@ -466,7 +476,127 @@ public class ZLMHttpHookListener { @@ -466,7 +476,127 @@ public class ZLMHttpHookListener {
466 streamInfo.getStream(), null); 476 streamInfo.getStream(), null);
467 } 477 }
468 } 478 }
469 - }else { 479 + }else if ("broadcast".equals(app)){
  480 + // 语音对讲推流 stream需要满足格式deviceId_channelId
  481 + if (regist && stream.indexOf("_") > 0) {
  482 + String[] streamArray = stream.split("_");
  483 + if (streamArray.length == 2) {
  484 + String deviceId = streamArray[0];
  485 + String channelId = streamArray[1];
  486 + Device device = deviceService.queryDevice(deviceId);
  487 + if (device != null) {
  488 + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
  489 + if (deviceChannel != null) {
  490 + if (audioBroadcastManager.exit(deviceId, channelId)) {
  491 + // 直接推流
  492 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, stream, null);
  493 + if (sendRtpItem == null) {
  494 + // TODO 可能数据错误,重新开启语音通道
  495 + }else {
  496 + String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
  497 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  498 + logger.info("rtp/{}开始向上级推流, 目标={}:{},SSRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
  499 + Map<String, Object> param = new HashMap<>(12);
  500 + param.put("vhost","__defaultVhost__");
  501 + param.put("app",sendRtpItem.getApp());
  502 + param.put("stream",sendRtpItem.getStreamId());
  503 + param.put("ssrc", sendRtpItem.getSsrc());
  504 + param.put("src_port", sendRtpItem.getLocalPort());
  505 + param.put("pt", sendRtpItem.getPt());
  506 + param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  507 + param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  508 +
  509 + JSONObject jsonObject;
  510 + if (sendRtpItem.isTcpActive()) {
  511 + jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
  512 + } else {
  513 + param.put("is_udp", is_Udp);
  514 + param.put("dst_url", sendRtpItem.getIp());
  515 + param.put("dst_port", sendRtpItem.getPort());
  516 + jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  517 + }
  518 + if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  519 + logger.info("[语音对讲] 自动推流成功, device: {}, channel: {}", deviceId, channelId);
  520 + }
  521 +
  522 + }
  523 + }else {
  524 + // 开启语音对讲通道
  525 + try {
  526 + playService.audioBroadcastCmd(device, channelId, 60, (msg)->{
  527 + logger.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId);
  528 + });
  529 + } catch (InvalidArgumentException | ParseException | SipException e) {
  530 + logger.error("[命令发送失败] 语音对讲: {}", e.getMessage());
  531 + }
  532 + }
  533 +
  534 + }
  535 + }
  536 + }
  537 + }
  538 +
  539 + }else if ("talk".equals(app)){
  540 + // 语音对讲推流 stream需要满足格式deviceId_channelId
  541 + if (regist && stream.indexOf("_") > 0) {
  542 + String[] streamArray = stream.split("_");
  543 + if (streamArray.length == 2) {
  544 + String deviceId = streamArray[0];
  545 + String channelId = streamArray[1];
  546 + Device device = deviceService.queryDevice(deviceId);
  547 + if (device != null) {
  548 + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
  549 + if (deviceChannel != null) {
  550 + if (audioBroadcastManager.exit(deviceId, channelId)) {
  551 + // 直接推流
  552 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, stream, null);
  553 + if (sendRtpItem == null) {
  554 + // TODO 可能数据错误,重新开启语音通道
  555 + }else {
  556 + String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
  557 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  558 + logger.info("rtp/{}开始向上级推流, 目标={}:{},SSRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
  559 + Map<String, Object> param = new HashMap<>(12);
  560 + param.put("vhost","__defaultVhost__");
  561 + param.put("app",sendRtpItem.getApp());
  562 + param.put("stream",sendRtpItem.getStreamId());
  563 + param.put("ssrc", sendRtpItem.getSsrc());
  564 + param.put("src_port", sendRtpItem.getLocalPort());
  565 + param.put("pt", sendRtpItem.getPt());
  566 + param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  567 + param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  568 +
  569 + JSONObject jsonObject;
  570 + if (sendRtpItem.isTcpActive()) {
  571 + jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
  572 + } else {
  573 + param.put("is_udp", is_Udp);
  574 + param.put("dst_url", sendRtpItem.getIp());
  575 + param.put("dst_port", sendRtpItem.getPort());
  576 + jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  577 + }
  578 + if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  579 + logger.info("[语音对讲] 自动推流成功, device: {}, channel: {}", deviceId, channelId);
  580 + }
  581 + }
  582 + }else {
  583 + // 开启语音对讲通道
  584 + MediaServerItem mediaServerForMinimumLoad = mediaServerService.getMediaServerForMinimumLoad();
  585 + playService.talk(mediaServerForMinimumLoad, device, channelId, (mediaServerItem, jsonObject)->{
  586 + System.out.println("开始推流");
  587 + }, eventResult -> {
  588 + System.out.println(eventResult.msg);
  589 + }, ()->{
  590 + System.out.println("超时");
  591 + });
  592 + }
  593 +
  594 + }
  595 + }
  596 + }
  597 + }
  598 +
  599 + }else{
470 if (!"rtp".equals(app)){ 600 if (!"rtp".equals(app)){
471 String type = OriginType.values()[item.getOriginType()].getType(); 601 String type = OriginType.values()[item.getOriginType()].getType();
472 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); 602 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
@@ -521,10 +651,23 @@ public class ZLMHttpHookListener { @@ -521,10 +651,23 @@ public class ZLMHttpHookListener {
521 if (sendRtpItem.getApp().equals(app)) { 651 if (sendRtpItem.getApp().equals(app)) {
522 String platformId = sendRtpItem.getPlatformId(); 652 String platformId = sendRtpItem.getPlatformId();
523 ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); 653 ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
  654 + Device device = deviceService.queryDevice(platformId);
524 655
525 try { 656 try {
526 - commanderFroPlatform.streamByeCmd(platform, sendRtpItem);  
527 - } catch (SipException | InvalidArgumentException | ParseException e) { 657 + if (platform != null) {
  658 + commanderFroPlatform.streamByeCmd(platform, sendRtpItem);
  659 + }else {
  660 + if (sendRtpItem.isOnlyAudio()) {
  661 + AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
  662 + if (device != null && audioBroadcastCatch != null) {
  663 +// cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null);
  664 + }
  665 + }else {
  666 + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), stream, sendRtpItem.getCallId());
  667 + }
  668 +
  669 + }
  670 + } catch (SipException | InvalidArgumentException | ParseException | SsrcTransactionNotFoundException e) {
528 logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); 671 logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
529 } 672 }
530 } 673 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -164,33 +164,6 @@ public class ZLMRTPServerFactory { @@ -164,33 +164,6 @@ public class ZLMRTPServerFactory {
164 return result; 164 return result;
165 } 165 }
166 166
167 -// private int getPortFromportRange(MediaServerItem mediaServerItem) {  
168 -// int currentPort = mediaServerItem.getCurrentPort();  
169 -// if (currentPort == 0) {  
170 -// String[] portRangeStrArray = mediaServerItem.getSendRtpPortRange().split(",");  
171 -// if (portRangeStrArray.length != 2) {  
172 -// portRangeArray[0] = 30000;  
173 -// portRangeArray[1] = 30500;  
174 -// }else {  
175 -// portRangeArray[0] = Integer.parseInt(portRangeStrArray[0]);  
176 -// portRangeArray[1] = Integer.parseInt(portRangeStrArray[1]);  
177 -// }  
178 -// }  
179 -//  
180 -// if (currentPort == 0 || currentPort++ > portRangeArray[1]) {  
181 -// currentPort = portRangeArray[0];  
182 -// mediaServerItem.setCurrentPort(currentPort);  
183 -// return portRangeArray[0];  
184 -// } else {  
185 -// if (currentPort % 2 == 1) {  
186 -// currentPort++;  
187 -// }  
188 -// currentPort++;  
189 -// mediaServerItem.setCurrentPort(currentPort);  
190 -// return currentPort;  
191 -// }  
192 -// }  
193 -  
194 /** 167 /**
195 * 创建一个国标推流 168 * 创建一个国标推流
196 * @param ip 推流ip 169 * @param ip 推流ip
src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java
@@ -38,6 +38,7 @@ public class ZlmHttpHookSubscribe { @@ -38,6 +38,7 @@ public class ZlmHttpHookSubscribe {
38 hookSubscribe.setExpires(expiresInstant); 38 hookSubscribe.setExpires(expiresInstant);
39 } 39 }
40 allSubscribes.computeIfAbsent(hookSubscribe.getHookType(), k -> new ConcurrentHashMap<>()).put(hookSubscribe, event); 40 allSubscribes.computeIfAbsent(hookSubscribe.getHookType(), k -> new ConcurrentHashMap<>()).put(hookSubscribe, event);
  41 + System.out.println(allSubscribes);
41 } 42 }
42 43
43 public ZlmHttpHookSubscribe.Event sendNotify(HookType type, JSONObject hookResponse) { 44 public ZlmHttpHookSubscribe.Event sendNotify(HookType type, JSONObject hookResponse) {
@@ -48,6 +49,7 @@ public class ZlmHttpHookSubscribe { @@ -48,6 +49,7 @@ public class ZlmHttpHookSubscribe {
48 } 49 }
49 for (IHookSubscribe key : eventMap.keySet()) { 50 for (IHookSubscribe key : eventMap.keySet()) {
50 Boolean result = null; 51 Boolean result = null;
  52 +
51 for (String s : key.getContent().keySet()) { 53 for (String s : key.getContent().keySet()) {
52 if (result == null) { 54 if (result == null) {
53 result = key.getContent().getString(s).equals(hookResponse.getString(s)); 55 result = key.getContent().getString(s).equals(hookResponse.getString(s));
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java
@@ -24,10 +24,26 @@ public class HookSubscribeFactory { @@ -24,10 +24,26 @@ public class HookSubscribeFactory {
24 return hookSubscribe; 24 return hookSubscribe;
25 } 25 }
26 26
  27 + public static HookSubscribeForStreamPush on_publish(String app, String stream, String scheam, String mediaServerId) {
  28 + HookSubscribeForStreamPush hookSubscribe = new HookSubscribeForStreamPush();
  29 + JSONObject subscribeKey = new com.alibaba.fastjson.JSONObject();
  30 + subscribeKey.put("app", app);
  31 + subscribeKey.put("stream", stream);
  32 + if (scheam != null) {
  33 + subscribeKey.put("schema", scheam);
  34 + }
  35 + subscribeKey.put("mediaServerId", mediaServerId);
  36 + hookSubscribe.setContent(subscribeKey);
  37 +
  38 + return hookSubscribe;
  39 + }
  40 +
  41 +
27 public static HookSubscribeForServerStarted on_server_started() { 42 public static HookSubscribeForServerStarted on_server_started() {
28 HookSubscribeForServerStarted hookSubscribe = new HookSubscribeForServerStarted(); 43 HookSubscribeForServerStarted hookSubscribe = new HookSubscribeForServerStarted();
29 hookSubscribe.setContent(new JSONObject()); 44 hookSubscribe.setContent(new JSONObject());
30 45
31 return hookSubscribe; 46 return hookSubscribe;
32 } 47 }
  48 +
33 } 49 }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamPush.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm.dto;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +
  5 +import java.time.Instant;
  6 +
  7 +/**
  8 + * hook订阅-开始推流
  9 + * @author lin
  10 + */
  11 +public class HookSubscribeForStreamPush implements IHookSubscribe{
  12 +
  13 + private HookType hookType = HookType.on_publish;
  14 +
  15 + private JSONObject content;
  16 +
  17 + private Instant expires;
  18 +
  19 + @Override
  20 + public HookType getHookType() {
  21 + return hookType;
  22 + }
  23 +
  24 + @Override
  25 + public JSONObject getContent() {
  26 + return content;
  27 + }
  28 +
  29 + public void setContent(JSONObject content) {
  30 + this.content = content;
  31 + }
  32 +
  33 + @Override
  34 + public Instant getExpires() {
  35 + return expires;
  36 + }
  37 +
  38 + @Override
  39 + public void setExpires(Instant expires) {
  40 + this.expires = expires;
  41 + }
  42 +}
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -11,11 +11,16 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; @@ -11,11 +11,16 @@ 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.bean.AudioBroadcastResult;
14 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; 15 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
15 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 16 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
16 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; 17 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
17 import org.springframework.web.context.request.async.DeferredResult; 18 import org.springframework.web.context.request.async.DeferredResult;
18 19
  20 +import javax.sip.InvalidArgumentException;
  21 +import javax.sip.SipException;
  22 +import java.text.ParseException;
  23 +
19 /** 24 /**
20 * 点播处理 25 * 点播处理
21 */ 26 */
@@ -23,6 +28,10 @@ public interface IPlayService { @@ -23,6 +28,10 @@ public interface IPlayService {
23 28
24 void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid); 29 void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
25 30
  31 + void talk(MediaServerItem mediaServerItem, Device device, String channelId,
  32 + ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
  33 + Runnable timeoutCallback);
  34 +
26 void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 35 void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
27 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, 36 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
28 InviteTimeOutCallback timeoutCallback, String uuid); 37 InviteTimeOutCallback timeoutCallback, String uuid);
@@ -44,6 +53,8 @@ public interface IPlayService { @@ -44,6 +53,8 @@ public interface IPlayService {
44 53
45 void zlmServerOnline(String mediaServerId); 54 void zlmServerOnline(String mediaServerId);
46 55
47 - void audioBroadcast(Device device, String channelId, int timeout, AudioBroadcastEvent event); 56 + AudioBroadcastResult audioBroadcast(Device device, String channelId);
48 void stopAudioBroadcast(String deviceId, String channelId); 57 void stopAudioBroadcast(String deviceId, String channelId);
  58 +
  59 + void audioBroadcastCmd(Device device, String channelId, int timeout, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
49 } 60 }
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -69,7 +69,7 @@ public class MediaServiceImpl implements IMediaService { @@ -69,7 +69,7 @@ public class MediaServiceImpl implements IMediaService {
69 JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class); 69 JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
70 JSONArray tracks = mediaJSON.getJSONArray("tracks"); 70 JSONArray tracks = mediaJSON.getJSONArray("tracks");
71 if (authority) { 71 if (authority) {
72 - streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr, calld); 72 + streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr, calld, true);
73 }else { 73 }else {
74 streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr,null, true); 74 streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr,null, true);
75 } 75 }
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -12,8 +12,10 @@ import javax.sip.SipException; @@ -12,8 +12,10 @@ import javax.sip.SipException;
12 import com.genersoft.iot.vmp.gb28181.bean.*; 12 import com.genersoft.iot.vmp.gb28181.bean.*;
13 import com.genersoft.iot.vmp.conf.exception.ControllerException; 13 import com.genersoft.iot.vmp.conf.exception.ControllerException;
14 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 14 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
15 -import com.genersoft.iot.vmp.gb28181.bean.*; 15 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
  16 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
16 import com.genersoft.iot.vmp.service.IDeviceService; 17 import com.genersoft.iot.vmp.service.IDeviceService;
  18 +import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
17 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 19 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
18 import org.slf4j.Logger; 20 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory; 21 import org.slf4j.LoggerFactory;
@@ -36,7 +38,6 @@ import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; @@ -36,7 +38,6 @@ import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
36 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 38 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
37 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 39 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
38 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 40 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
39 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;  
40 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 41 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
41 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; 42 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
42 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; 43 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
@@ -54,33 +55,10 @@ import com.genersoft.iot.vmp.service.bean.PlayBackResult; @@ -54,33 +55,10 @@ import com.genersoft.iot.vmp.service.bean.PlayBackResult;
54 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 55 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
55 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 56 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
56 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 57 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
57 -import com.genersoft.iot.vmp.utils.redis.RedisUtil;  
58 -import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;  
59 -import com.genersoft.iot.vmp.utils.DateUtil;  
60 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 58 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
61 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; 59 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
62 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; 60 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
63 61
64 -import gov.nist.javax.sip.stack.SIPDialog;  
65 -import org.slf4j.Logger;  
66 -import org.slf4j.LoggerFactory;  
67 -import org.springframework.beans.factory.annotation.Autowired;  
68 -import org.springframework.http.HttpStatus;  
69 -import org.springframework.http.ResponseEntity;  
70 -import org.springframework.stereotype.Service;  
71 -import org.springframework.util.ResourceUtils;  
72 -import org.springframework.web.context.request.async.DeferredResult;  
73 -  
74 -import javax.sip.ResponseEvent;  
75 -import javax.sip.SipException;  
76 -import java.io.FileNotFoundException;  
77 -import java.math.BigDecimal;  
78 -import java.text.ParseException;  
79 -import java.math.RoundingMode;  
80 -import java.util.*;  
81 -import java.util.stream.Collectors;  
82 -import java.util.stream.Stream;  
83 -  
84 @SuppressWarnings(value = {"rawtypes", "unchecked"}) 62 @SuppressWarnings(value = {"rawtypes", "unchecked"})
85 @Service 63 @Service
86 public class PlayServiceImpl implements IPlayService { 64 public class PlayServiceImpl implements IPlayService {
@@ -97,7 +75,10 @@ public class PlayServiceImpl implements IPlayService { @@ -97,7 +75,10 @@ public class PlayServiceImpl implements IPlayService {
97 private AudioBroadcastManager audioBroadcastManager; 75 private AudioBroadcastManager audioBroadcastManager;
98 76
99 @Autowired 77 @Autowired
100 - private SIPCommanderFroPlatform sipCommanderFroPlatform; 78 + private IDeviceService deviceService;
  79 +
  80 + @Autowired
  81 + private ISIPCommanderForPlatform sipCommanderFroPlatform;
101 82
102 @Autowired 83 @Autowired
103 private IRedisCatchStorage redisCatchStorage; 84 private IRedisCatchStorage redisCatchStorage;
@@ -123,10 +104,6 @@ public class PlayServiceImpl implements IPlayService { @@ -123,10 +104,6 @@ public class PlayServiceImpl implements IPlayService {
123 @Autowired 104 @Autowired
124 private VideoStreamSessionManager streamSession; 105 private VideoStreamSessionManager streamSession;
125 106
126 -  
127 - @Autowired  
128 - private IDeviceService deviceService;  
129 -  
130 @Autowired 107 @Autowired
131 private UserSetting userSetting; 108 private UserSetting userSetting;
132 109
@@ -145,7 +122,6 @@ public class PlayServiceImpl implements IPlayService { @@ -145,7 +122,6 @@ public class PlayServiceImpl implements IPlayService {
145 private ThreadPoolTaskExecutor taskExecutor; 122 private ThreadPoolTaskExecutor taskExecutor;
146 123
147 124
148 -  
149 @Override 125 @Override
150 public PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, 126 public PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId,
151 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, 127 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
@@ -169,15 +145,15 @@ public class PlayServiceImpl implements IPlayService { @@ -169,15 +145,15 @@ public class PlayServiceImpl implements IPlayService {
169 StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); 145 StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
170 playResult.setDevice(device); 146 playResult.setDevice(device);
171 147
172 - result.onCompletion(()->{ 148 + result.onCompletion(() -> {
173 // 点播结束时调用截图接口 149 // 点播结束时调用截图接口
174 - taskExecutor.execute(()->{ 150 + taskExecutor.execute(() -> {
175 // TODO 应该在上流时调用更好,结束也可能是错误结束 151 // TODO 应该在上流时调用更好,结束也可能是错误结束
176 - String path = "snap";  
177 - String fileName = deviceId + "_" + channelId + ".jpg";  
178 - WVPResult wvpResult = (WVPResult)result.getResult(); 152 + String path = "snap";
  153 + String fileName = deviceId + "_" + channelId + ".jpg";
  154 + WVPResult wvpResult = (WVPResult) result.getResult();
179 if (Objects.requireNonNull(wvpResult).getCode() == 0) { 155 if (Objects.requireNonNull(wvpResult).getCode() == 0) {
180 - StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData(); 156 + StreamInfo streamInfoForSuccess = (StreamInfo) wvpResult.getData();
181 MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId()); 157 MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());
182 String streamUrl = streamInfoForSuccess.getFmp4(); 158 String streamUrl = streamInfoForSuccess.getFmp4();
183 // 请求截图 159 // 请求截图
@@ -201,7 +177,7 @@ public class PlayServiceImpl implements IPlayService { @@ -201,7 +177,7 @@ public class PlayServiceImpl implements IPlayService {
201 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); 177 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
202 178
203 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId); 179 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
204 - if(rtpInfo.getInteger("code") == 0){ 180 + if (rtpInfo.getInteger("code") == 0) {
205 if (rtpInfo.getBoolean("exist")) { 181 if (rtpInfo.getBoolean("exist")) {
206 int localPort = rtpInfo.getInteger("local_port"); 182 int localPort = rtpInfo.getInteger("local_port");
207 if (localPort == 0) { 183 if (localPort == 0) {
@@ -214,7 +190,7 @@ public class PlayServiceImpl implements IPlayService { @@ -214,7 +190,7 @@ public class PlayServiceImpl implements IPlayService {
214 190
215 resultHolder.invokeAllResult(msg); 191 resultHolder.invokeAllResult(msg);
216 return playResult; 192 return playResult;
217 - }else { 193 + } else {
218 WVPResult wvpResult = new WVPResult(); 194 WVPResult wvpResult = new WVPResult();
219 wvpResult.setCode(ErrorCode.SUCCESS.getCode()); 195 wvpResult.setCode(ErrorCode.SUCCESS.getCode());
220 wvpResult.setMsg(ErrorCode.SUCCESS.getMsg()); 196 wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
@@ -227,12 +203,12 @@ public class PlayServiceImpl implements IPlayService { @@ -227,12 +203,12 @@ public class PlayServiceImpl implements IPlayService {
227 } 203 }
228 } 204 }
229 205
230 - }else { 206 + } else {
231 redisCatchStorage.stopPlay(streamInfo); 207 redisCatchStorage.stopPlay(streamInfo);
232 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 208 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
233 streamInfo = null; 209 streamInfo = null;
234 } 210 }
235 - }else { 211 + } else {
236 //zlm连接失败 212 //zlm连接失败
237 redisCatchStorage.stopPlay(streamInfo); 213 redisCatchStorage.stopPlay(streamInfo);
238 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 214 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
@@ -246,7 +222,7 @@ public class PlayServiceImpl implements IPlayService { @@ -246,7 +222,7 @@ public class PlayServiceImpl implements IPlayService {
246 } 222 }
247 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false); 223 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);
248 logger.info(JSONObject.toJSONString(ssrcInfo)); 224 logger.info(JSONObject.toJSONString(ssrcInfo));
249 - play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response)->{ 225 + play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response) -> {
250 if (hookEvent != null) { 226 if (hookEvent != null) {
251 hookEvent.response(mediaServerItem, response); 227 hookEvent.response(mediaServerItem, response);
252 } 228 }
@@ -260,13 +236,13 @@ public class PlayServiceImpl implements IPlayService { @@ -260,13 +236,13 @@ public class PlayServiceImpl implements IPlayService {
260 if (errorEvent != null) { 236 if (errorEvent != null) {
261 errorEvent.response(event); 237 errorEvent.response(event);
262 } 238 }
263 - }, (code, msgStr)->{ 239 + }, (code, msgStr) -> {
264 // invite点播超时 240 // invite点播超时
265 WVPResult wvpResult = new WVPResult(); 241 WVPResult wvpResult = new WVPResult();
266 wvpResult.setCode(ErrorCode.ERROR100.getCode()); 242 wvpResult.setCode(ErrorCode.ERROR100.getCode());
267 if (code == 0) { 243 if (code == 0) {
268 wvpResult.setMsg("点播超时,请稍候重试"); 244 wvpResult.setMsg("点播超时,请稍候重试");
269 - }else if (code == 1) { 245 + } else if (code == 1) {
270 wvpResult.setMsg("收流超时,请稍候重试"); 246 wvpResult.setMsg("收流超时,请稍候重试");
271 } 247 }
272 msg.setData(wvpResult); 248 msg.setData(wvpResult);
@@ -277,6 +253,186 @@ public class PlayServiceImpl implements IPlayService { @@ -277,6 +253,186 @@ public class PlayServiceImpl implements IPlayService {
277 return playResult; 253 return playResult;
278 } 254 }
279 255
  256 + @Override
  257 + public void talk(MediaServerItem mediaServerItem, Device device, String channelId,
  258 + ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
  259 + Runnable timeoutCallback) {
  260 + String streamId = null;
  261 + if (mediaServerItem.isRtpEnable()) {
  262 + streamId = String.format("%s_%s", device.getDeviceId(), channelId);
  263 + }
  264 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);
  265 + logger.info("[对讲开始] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  266 + // 超时处理
  267 + String timeOutTaskKey = UUID.randomUUID().toString();
  268 + SSRCInfo finalSsrcInfo = ssrcInfo;
  269 + System.out.println("设置超时任务: " + timeOutTaskKey);
  270 + dynamicTask.startDelay(timeOutTaskKey, () -> {
  271 +
  272 + logger.info("[对讲超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, finalSsrcInfo.getPort(), finalSsrcInfo.getSsrc());
  273 + timeoutCallback.run();
  274 + // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
  275 + try {
  276 + cmder.streamByeCmd(device, channelId, finalSsrcInfo.getStream(), null);
  277 + } catch (InvalidArgumentException | ParseException | SipException e) {
  278 + logger.error("[对讲超时], 发送BYE失败 {}", e.getMessage());
  279 + } catch (SsrcTransactionNotFoundException e) {
  280 + timeoutCallback.run();
  281 + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  282 + mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());
  283 + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  284 + }
  285 + }, userSetting.getPlayTimeout());
  286 + final String ssrc = ssrcInfo.getSsrc();
  287 + final String stream = ssrcInfo.getStream();
  288 + //端口获取失败的ssrcInfo 没有必要发送点播指令
  289 + if (ssrcInfo.getPort() <= 0) {
  290 + logger.info("[对讲] 端口分配异常,deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo);
  291 + return;
  292 + }
  293 + try {
  294 + String callId = SipUtils.getNewCallId();
  295 + cmder.talkStreamCmd(mediaServerItem, ssrcInfo, device, channelId, callId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
  296 + logger.info("[对讲] 流已生成, 开始推流: " + response.toJSONString());
  297 + dynamicTask.stop(timeOutTaskKey);
  298 + // TODO 暂不做处理
  299 + }, (MediaServerItem mediaServerItemInuse, JSONObject json) -> {
  300 + logger.info("[对讲] 开始推流: " + json.toJSONString());
  301 + dynamicTask.stop(timeOutTaskKey);
  302 + // 获取远程IP端口 作为回复语音流的地址
  303 + String ip = json.getString("ip");
  304 + Integer port = json.getInteger("port");
  305 + logger.info("[远端设备开始推流]{}/{}, 来自ip:{}, 端口:{}", device.getDeviceId(), channelId, ip, port);
  306 + // 查看平台推流是否就绪
  307 + Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItemInuse, "talk", stream);
  308 + if (!ready) {
  309 + try {
  310 + cmder.streamByeCmd(device, channelId, finalSsrcInfo.getStream(), null);
  311 + } catch (InvalidArgumentException | ParseException | SipException e) {
  312 + logger.error("[对讲超时], 发送BYE失败 {}", e.getMessage());
  313 + } catch (SsrcTransactionNotFoundException e) {
  314 + timeoutCallback.run();
  315 + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  316 + mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());
  317 + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  318 + }
  319 + }else {
  320 + SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, ip, port, ssrcInfo.getSsrc(), device.getDeviceId(),
  321 + device.getDeviceId(), channelId,
  322 + false);
  323 +
  324 + sendRtpItem.setTcpActive(false);
  325 + if (sendRtpItem == null || sendRtpItem.getLocalPort() == 0) {
  326 + logger.warn("服务器端口资源不足");
  327 + try {
  328 + cmder.streamByeCmd(device, channelId, finalSsrcInfo.getStream(), null);
  329 + } catch (InvalidArgumentException | ParseException | SipException e) {
  330 + logger.error("[对讲超时], 发送BYE失败 {}", e.getMessage());
  331 + } catch (SsrcTransactionNotFoundException e) {
  332 + timeoutCallback.run();
  333 + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  334 + mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());
  335 + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  336 + }
  337 + return;
  338 + }
  339 + sendRtpItem.setCallId(callId);
  340 + sendRtpItem.setPlayType(InviteStreamType.TALK);
  341 + sendRtpItem.setStatus(1);
  342 + sendRtpItem.setIp(ip);
  343 + sendRtpItem.setPort(port);
  344 + sendRtpItem.setTcpActive(false);
  345 + sendRtpItem.setStreamId(ssrcInfo.getStream());
  346 + sendRtpItem.setApp("talk");
  347 + sendRtpItem.setSsrc(ssrc);
  348 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  349 +
  350 + Map<String, Object> param = new HashMap<>(12);
  351 + param.put("vhost","__defaultVhost__");
  352 + param.put("app",sendRtpItem.getApp());
  353 + param.put("stream",sendRtpItem.getStreamId());
  354 + param.put("ssrc", sendRtpItem.getSsrc());
  355 + param.put("src_port", sendRtpItem.getLocalPort());
  356 + param.put("pt", sendRtpItem.getPt());
  357 + param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  358 + param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  359 + JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaServerItemInuse, param);
  360 + System.out.println(11111);
  361 + System.out.println(jsonObject);
  362 + }
  363 +
  364 + }, (event) -> {
  365 +// ResponseEvent responseEvent = (ResponseEvent) event.event;
  366 +// String contentString = new String(responseEvent.getResponse().getRawContent());
  367 +// // 获取ssrc
  368 +// int ssrcIndex = contentString.indexOf("y=");
  369 +// // 检查是否有y字段
  370 +// if (ssrcIndex >= 0) {
  371 +// //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  372 +// String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  373 +// // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  374 +// if (ssrc.equals(ssrcInResponse)) {
  375 +// return;
  376 +// }
  377 +// logger.info("[对讲消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  378 +// if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
  379 +// logger.info("[对讲消息] SSRC修正 {}->{}", ssrc, ssrcInResponse);
  380 +//
  381 +// if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
  382 +// // ssrc 不可用
  383 +// // 释放ssrc
  384 +// mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  385 +// streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  386 +// event.msg = "下级自定义了ssrc,但是此ssrc不可用";
  387 +// event.statusCode = 400;
  388 +// errorEvent.response(event);
  389 +// return;
  390 +// }
  391 +//
  392 +// // 单端口模式streamId也有变化,需要重新设置监听
  393 +// if (!mediaServerItem.isRtpEnable()) {
  394 +// // 添加订阅
  395 +// HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
  396 +// subscribe.removeSubscribe(hookSubscribe);
  397 +// hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
  398 +// subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
  399 +// logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  400 +// dynamicTask.stop(timeOutTaskKey);
  401 +// // hook响应
  402 +// onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid);
  403 +// hookEvent.response(mediaServerItemInUse, response);
  404 +// });
  405 +// }
  406 +// // 关闭rtp server
  407 +// mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());
  408 +// // 重新开启ssrc server
  409 +// mediaServerService.openRTPServer(mediaServerItem, finalSsrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), false, finalSsrcInfo.getPort());
  410 +//
  411 +// }
  412 +// }
  413 + }, (event) -> {
  414 + dynamicTask.stop(timeOutTaskKey);
  415 + mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());
  416 + // 释放ssrc
  417 + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  418 +
  419 + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  420 + errorEvent.response(event);
  421 + });
  422 + } catch (InvalidArgumentException | SipException | ParseException e) {
  423 +
  424 + logger.error("[命令发送失败] 对讲消息: {}", e.getMessage());
  425 + dynamicTask.stop(timeOutTaskKey);
  426 + mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());
  427 + // 释放ssrc
  428 + mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
  429 +
  430 + streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
  431 + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null));
  432 + eventResult.msg = "命令发送失败";
  433 + errorEvent.response(eventResult);
  434 + }
  435 + }
280 436
281 437
282 @Override 438 @Override
@@ -291,12 +447,12 @@ public class PlayServiceImpl implements IPlayService { @@ -291,12 +447,12 @@ public class PlayServiceImpl implements IPlayService {
291 if (ssrcInfo == null) { 447 if (ssrcInfo == null) {
292 ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false); 448 ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);
293 } 449 }
294 - logger.info("[点播开始] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck() ); 450 + logger.info("[点播开始] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
295 // 超时处理 451 // 超时处理
296 String timeOutTaskKey = UUID.randomUUID().toString(); 452 String timeOutTaskKey = UUID.randomUUID().toString();
297 SSRCInfo finalSsrcInfo = ssrcInfo; 453 SSRCInfo finalSsrcInfo = ssrcInfo;
298 System.out.println("设置超时任务: " + timeOutTaskKey); 454 System.out.println("设置超时任务: " + timeOutTaskKey);
299 - dynamicTask.startDelay( timeOutTaskKey,()->{ 455 + dynamicTask.startDelay(timeOutTaskKey, () -> {
300 456
301 logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, finalSsrcInfo.getPort(), finalSsrcInfo.getSsrc()); 457 logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, finalSsrcInfo.getPort(), finalSsrcInfo.getSsrc());
302 timeoutCallback.run(1, "收流超时"); 458 timeoutCallback.run(1, "收流超时");
@@ -315,7 +471,7 @@ public class PlayServiceImpl implements IPlayService { @@ -315,7 +471,7 @@ public class PlayServiceImpl implements IPlayService {
315 final String ssrc = ssrcInfo.getSsrc(); 471 final String ssrc = ssrcInfo.getSsrc();
316 final String stream = ssrcInfo.getStream(); 472 final String stream = ssrcInfo.getStream();
317 //端口获取失败的ssrcInfo 没有必要发送点播指令 473 //端口获取失败的ssrcInfo 没有必要发送点播指令
318 - if(ssrcInfo.getPort() <= 0){ 474 + if (ssrcInfo.getPort() <= 0) {
319 logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo); 475 logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo);
320 return; 476 return;
321 } 477 }
@@ -330,7 +486,7 @@ public class PlayServiceImpl implements IPlayService { @@ -330,7 +486,7 @@ public class PlayServiceImpl implements IPlayService {
330 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); 486 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
331 487
332 }, (event) -> { 488 }, (event) -> {
333 - ResponseEvent responseEvent = (ResponseEvent)event.event; 489 + ResponseEvent responseEvent = (ResponseEvent) event.event;
334 String contentString = new String(responseEvent.getResponse().getRawContent()); 490 String contentString = new String(responseEvent.getResponse().getRawContent());
335 // 获取ssrc 491 // 获取ssrc
336 int ssrcIndex = contentString.indexOf("y="); 492 int ssrcIndex = contentString.indexOf("y=");
@@ -342,7 +498,7 @@ public class PlayServiceImpl implements IPlayService { @@ -342,7 +498,7 @@ public class PlayServiceImpl implements IPlayService {
342 if (ssrc.equals(ssrcInResponse)) { 498 if (ssrc.equals(ssrcInResponse)) {
343 return; 499 return;
344 } 500 }
345 - logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse ); 501 + logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
346 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { 502 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
347 logger.info("[点播消息] SSRC修正 {}->{}", ssrc, ssrcInResponse); 503 logger.info("[点播消息] SSRC修正 {}->{}", ssrc, ssrcInResponse);
348 504
@@ -363,13 +519,13 @@ public class PlayServiceImpl implements IPlayService { @@ -363,13 +519,13 @@ public class PlayServiceImpl implements IPlayService {
363 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); 519 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
364 subscribe.removeSubscribe(hookSubscribe); 520 subscribe.removeSubscribe(hookSubscribe);
365 hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); 521 hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
366 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{  
367 - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());  
368 - dynamicTask.stop(timeOutTaskKey);  
369 - // hook响应  
370 - onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid);  
371 - hookEvent.response(mediaServerItemInUse, response);  
372 - }); 522 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
  523 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  524 + dynamicTask.stop(timeOutTaskKey);
  525 + // hook响应
  526 + onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid);
  527 + hookEvent.response(mediaServerItemInUse, response);
  528 + });
373 } 529 }
374 // 关闭rtp server 530 // 关闭rtp server
375 mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream()); 531 mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());
@@ -441,7 +597,7 @@ public class PlayServiceImpl implements IPlayService { @@ -441,7 +597,7 @@ public class PlayServiceImpl implements IPlayService {
441 MediaServerItem mediaServerItem; 597 MediaServerItem mediaServerItem;
442 if (mediaServerId == null) { 598 if (mediaServerId == null) {
443 mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(); 599 mediaServerItem = mediaServerService.getMediaServerForMinimumLoad();
444 - }else { 600 + } else {
445 mediaServerItem = mediaServerService.getOne(mediaServerId); 601 mediaServerItem = mediaServerService.getOne(mediaServerId);
446 } 602 }
447 if (mediaServerItem == null) { 603 if (mediaServerItem == null) {
@@ -452,8 +608,8 @@ public class PlayServiceImpl implements IPlayService { @@ -452,8 +608,8 @@ public class PlayServiceImpl implements IPlayService {
452 608
453 @Override 609 @Override
454 public DeferredResult<WVPResult<StreamInfo>> playBack(String deviceId, String channelId, String startTime, 610 public DeferredResult<WVPResult<StreamInfo>> playBack(String deviceId, String channelId, String startTime,
455 - String endTime,InviteStreamCallback inviteStreamCallback,  
456 - PlayBackCallback callback) { 611 + String endTime, InviteStreamCallback inviteStreamCallback,
  612 + PlayBackCallback callback) {
457 Device device = storager.queryVideoDevice(deviceId); 613 Device device = storager.queryVideoDevice(deviceId);
458 if (device == null) { 614 if (device == null) {
459 return null; 615 return null;
@@ -466,9 +622,9 @@ public class PlayServiceImpl implements IPlayService { @@ -466,9 +622,9 @@ public class PlayServiceImpl implements IPlayService {
466 622
467 @Override 623 @Override
468 public DeferredResult<WVPResult<StreamInfo>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, 624 public DeferredResult<WVPResult<StreamInfo>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
469 - String deviceId, String channelId, String startTime,  
470 - String endTime, InviteStreamCallback infoCallBack,  
471 - PlayBackCallback playBackCallback) { 625 + String deviceId, String channelId, String startTime,
  626 + String endTime, InviteStreamCallback infoCallBack,
  627 + PlayBackCallback playBackCallback) {
472 if (mediaServerItem == null || ssrcInfo == null) { 628 if (mediaServerItem == null || ssrcInfo == null) {
473 return null; 629 return null;
474 } 630 }
@@ -485,7 +641,7 @@ public class PlayServiceImpl implements IPlayService { @@ -485,7 +641,7 @@ public class PlayServiceImpl implements IPlayService {
485 requestMessage.setKey(key); 641 requestMessage.setKey(key);
486 PlayBackResult<RequestMessage> playBackResult = new PlayBackResult<>(); 642 PlayBackResult<RequestMessage> playBackResult = new PlayBackResult<>();
487 String playBackTimeOutTaskKey = UUID.randomUUID().toString(); 643 String playBackTimeOutTaskKey = UUID.randomUUID().toString();
488 - dynamicTask.startDelay(playBackTimeOutTaskKey, ()->{ 644 + dynamicTask.startDelay(playBackTimeOutTaskKey, () -> {
489 logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId)); 645 logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
490 playBackResult.setCode(ErrorCode.ERROR100.getCode()); 646 playBackResult.setCode(ErrorCode.ERROR100.getCode());
491 playBackResult.setMsg("回放超时"); 647 playBackResult.setMsg("回放超时");
@@ -545,7 +701,7 @@ public class PlayServiceImpl implements IPlayService { @@ -545,7 +701,7 @@ public class PlayServiceImpl implements IPlayService {
545 cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack, 701 cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack,
546 hookEvent, eventResult -> { 702 hookEvent, eventResult -> {
547 if (eventResult.type == SipSubscribe.EventResultType.response) { 703 if (eventResult.type == SipSubscribe.EventResultType.response) {
548 - ResponseEvent responseEvent = (ResponseEvent)eventResult.event; 704 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
549 String contentString = new String(responseEvent.getResponse().getRawContent()); 705 String contentString = new String(responseEvent.getResponse().getRawContent());
550 // 获取ssrc 706 // 获取ssrc
551 int ssrcIndex = contentString.indexOf("y="); 707 int ssrcIndex = contentString.indexOf("y=");
@@ -557,7 +713,7 @@ public class PlayServiceImpl implements IPlayService { @@ -557,7 +713,7 @@ public class PlayServiceImpl implements IPlayService {
557 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { 713 if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
558 return; 714 return;
559 } 715 }
560 - logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse ); 716 + logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
561 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { 717 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
562 logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); 718 logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
563 719
@@ -578,7 +734,7 @@ public class PlayServiceImpl implements IPlayService { @@ -578,7 +734,7 @@ public class PlayServiceImpl implements IPlayService {
578 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); 734 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
579 subscribe.removeSubscribe(hookSubscribe); 735 subscribe.removeSubscribe(hookSubscribe);
580 hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); 736 hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
581 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{ 737 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
582 logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); 738 logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
583 dynamicTask.stop(playBackTimeOutTaskKey); 739 dynamicTask.stop(playBackTimeOutTaskKey);
584 // hook响应 740 // hook响应
@@ -614,7 +770,7 @@ public class PlayServiceImpl implements IPlayService { @@ -614,7 +770,7 @@ public class PlayServiceImpl implements IPlayService {
614 MediaServerItem newMediaServerItem = getNewMediaServerItem(device); 770 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
615 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true, true); 771 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true, true);
616 772
617 - return download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed,infoCallBack, hookCallBack); 773 + return download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, infoCallBack, hookCallBack);
618 } 774 }
619 775
620 @Override 776 @Override
@@ -640,7 +796,7 @@ public class PlayServiceImpl implements IPlayService { @@ -640,7 +796,7 @@ public class PlayServiceImpl implements IPlayService {
640 downloadResult.setData(requestMessage); 796 downloadResult.setData(requestMessage);
641 797
642 String downLoadTimeOutTaskKey = UUID.randomUUID().toString(); 798 String downLoadTimeOutTaskKey = UUID.randomUUID().toString();
643 - dynamicTask.startDelay(downLoadTimeOutTaskKey, ()->{ 799 + dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> {
644 logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId)); 800 logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
645 wvpResult.setCode(ErrorCode.ERROR100.getCode()); 801 wvpResult.setCode(ErrorCode.ERROR100.getCode());
646 wvpResult.setMsg("录像下载请求超时"); 802 wvpResult.setMsg("录像下载请求超时");
@@ -723,15 +879,15 @@ public class PlayServiceImpl implements IPlayService { @@ -723,15 +879,15 @@ public class PlayServiceImpl implements IPlayService {
723 879
724 if (duration == 0) { 880 if (duration == 0) {
725 streamInfo.setProgress(0); 881 streamInfo.setProgress(0);
726 - }else { 882 + } else {
727 String startTime = streamInfo.getStartTime(); 883 String startTime = streamInfo.getStartTime();
728 String endTime = streamInfo.getEndTime(); 884 String endTime = streamInfo.getEndTime();
729 long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); 885 long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
730 long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); 886 long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
731 887
732 - BigDecimal currentCount = new BigDecimal(duration/1000);  
733 - BigDecimal totalCount = new BigDecimal(end-start);  
734 - BigDecimal divide = currentCount.divide(totalCount,2, RoundingMode.HALF_UP); 888 + BigDecimal currentCount = new BigDecimal(duration / 1000);
  889 + BigDecimal totalCount = new BigDecimal(end - start);
  890 + BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP);
735 double process = divide.doubleValue(); 891 double process = divide.doubleValue();
736 streamInfo.setProgress(process); 892 streamInfo.setProgress(process);
737 } 893 }
@@ -762,7 +918,7 @@ public class PlayServiceImpl implements IPlayService { @@ -762,7 +918,7 @@ public class PlayServiceImpl implements IPlayService {
762 public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId) { 918 public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId) {
763 String streamId = resonse.getString("stream"); 919 String streamId = resonse.getString("stream");
764 JSONArray tracks = resonse.getJSONArray("tracks"); 920 JSONArray tracks = resonse.getJSONArray("tracks");
765 - StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem,"rtp", streamId, tracks, null); 921 + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, "rtp", streamId, tracks, null);
766 streamInfo.setDeviceID(deviceId); 922 streamInfo.setDeviceID(deviceId);
767 streamInfo.setChannelId(channelId); 923 streamInfo.setChannelId(channelId);
768 return streamInfo; 924 return streamInfo;
@@ -788,7 +944,7 @@ public class PlayServiceImpl implements IPlayService { @@ -788,7 +944,7 @@ public class PlayServiceImpl implements IPlayService {
788 List<SsrcTransaction> allSsrc = streamSession.getAllSsrc(); 944 List<SsrcTransaction> allSsrc = streamSession.getAllSsrc();
789 if (allSsrc.size() > 0) { 945 if (allSsrc.size() > 0) {
790 for (SsrcTransaction ssrcTransaction : allSsrc) { 946 for (SsrcTransaction ssrcTransaction : allSsrc) {
791 - if(ssrcTransaction.getMediaServerId().equals(mediaServerId)) { 947 + if (ssrcTransaction.getMediaServerId().equals(mediaServerId)) {
792 Device device = deviceService.queryDevice(ssrcTransaction.getDeviceId()); 948 Device device = deviceService.queryDevice(ssrcTransaction.getDeviceId());
793 if (device == null) { 949 if (device == null) {
794 continue; 950 continue;
@@ -806,10 +962,36 @@ public class PlayServiceImpl implements IPlayService { @@ -806,10 +962,36 @@ public class PlayServiceImpl implements IPlayService {
806 } 962 }
807 963
808 @Override 964 @Override
809 - public void audioBroadcast(Device device, String channelId, int timeout, AudioBroadcastEvent event) { 965 + public AudioBroadcastResult audioBroadcast(Device device, String channelId) {
  966 + if (device == null || channelId == null) {
  967 + return null;
  968 + }
  969 + logger.info("[语音喊话] device: {}, channel: {}", device.getDeviceId(), channelId);
  970 + DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
  971 + if (deviceChannel == null) {
  972 + logger.warn("开启语音广播的时候未找到通道: {}", channelId);
  973 + return null;
  974 + }
  975 + MediaServerItem mediaServerItem = mediaServerService.getMediaServerForMinimumLoad();
  976 +// String app = "broadcast";
  977 + // TODO 从sip user agent中判断是什么品牌设备,大华默认使用talk模式,其他使用broadcast模式
  978 + String app = "talk";
  979 + String stream = device.getDeviceId() + "_" + channelId;
  980 + StreamInfo broadcast = mediaService.getStreamInfoByAppAndStream(mediaServerItem, "broadcast", stream, null, null, null, false);
  981 + AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult();
  982 + audioBroadcastResult.setApp(app);
  983 + audioBroadcastResult.setStream(stream);
  984 + audioBroadcastResult.setStreamInfo(mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, stream, null, null, null,false));
  985 + audioBroadcastResult.setCodec("G.711");
  986 + return audioBroadcastResult;
  987 + }
  988 +
  989 + @Override
  990 + public void audioBroadcastCmd(Device device, String channelId, int timeout, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException {
810 if (device == null || channelId == null) { 991 if (device == null || channelId == null) {
811 return; 992 return;
812 } 993 }
  994 + logger.info("[语音喊话] device: {}, channel: {}", device.getDeviceId(), channelId);
813 DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId); 995 DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
814 if (deviceChannel == null) { 996 if (deviceChannel == null) {
815 logger.warn("开启语音广播的时候未找到通道: {}", channelId); 997 logger.warn("开启语音广播的时候未找到通道: {}", channelId);
@@ -818,7 +1000,7 @@ public class PlayServiceImpl implements IPlayService { @@ -818,7 +1000,7 @@ public class PlayServiceImpl implements IPlayService {
818 } 1000 }
819 // 查询通道使用状态 1001 // 查询通道使用状态
820 if (audioBroadcastManager.exit(device.getDeviceId(), channelId)) { 1002 if (audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
821 - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null); 1003 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
822 if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) { 1004 if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) {
823 // 查询流是否存在,不存在则认为是异常状态 1005 // 查询流是否存在,不存在则认为是异常状态
824 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId()); 1006 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
@@ -827,8 +1009,8 @@ public class PlayServiceImpl implements IPlayService { @@ -827,8 +1009,8 @@ public class PlayServiceImpl implements IPlayService {
827 logger.warn("语音广播已经开启: {}", channelId); 1009 logger.warn("语音广播已经开启: {}", channelId);
828 event.call("语音广播已经开启"); 1010 event.call("语音广播已经开启");
829 return; 1011 return;
830 - }else {  
831 - audioBroadcastManager.del(deviceChannel.getDeviceId(),channelId); 1012 + } else {
  1013 + audioBroadcastManager.del(deviceChannel.getDeviceId(), channelId);
832 redisCatchStorage.deleteSendRTPServer(device.getDeviceId(), channelId, sendRtpItem.getCallId(), sendRtpItem.getStreamId()); 1014 redisCatchStorage.deleteSendRTPServer(device.getDeviceId(), channelId, sendRtpItem.getCallId(), sendRtpItem.getStreamId());
833 } 1015 }
834 } 1016 }
@@ -847,39 +1029,33 @@ public class PlayServiceImpl implements IPlayService { @@ -847,39 +1029,33 @@ public class PlayServiceImpl implements IPlayService {
847 }); 1029 });
848 } 1030 }
849 1031
  1032 +
  1033 +
850 @Override 1034 @Override
851 - public void stopAudioBroadcast(String deviceId, String channelId){ 1035 + public void stopAudioBroadcast(String deviceId, String channelId) {
852 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(deviceId, channelId); 1036 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(deviceId, channelId);
853 if (audioBroadcastCatch != null) { 1037 if (audioBroadcastCatch != null) {
854 1038
855 - try {  
856 - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null);  
857 - if (sendRtpItem != null) {  
858 - redisCatchStorage.deleteSendRTPServer(deviceId, sendRtpItem.getChannelId(), null, null);  
859 - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());  
860 - Map<String, Object> param = new HashMap<>();  
861 - param.put("vhost", "__defaultVhost__");  
862 - param.put("app", sendRtpItem.getApp());  
863 - param.put("stream", sendRtpItem.getStreamId());  
864 - zlmresTfulUtils.stopSendRtp(mediaInfo, param);  
865 - // 立刻结束设备的推流,等待自行结束太慢  
866 - zlmresTfulUtils.closeStreams(mediaInfo, sendRtpItem.getApp(), sendRtpItem.getStreamId());  
867 - }  
868 - if (audioBroadcastCatch.getStatus() == AudioBroadcastCatchStatus.Ok) {  
869 - cmder.streamByeCmd(audioBroadcastCatch.getDialog(), audioBroadcastCatch.getChannelId(), audioBroadcastCatch.getRequest(), null);  
870 - }  
871 - audioBroadcastManager.del(deviceId, channelId);  
872 -  
873 - } catch (SipException e) {  
874 - throw new RuntimeException(e);  
875 - } catch (ParseException e) {  
876 - throw new RuntimeException(e);  
877 - } catch (InvalidArgumentException e) {  
878 - throw new RuntimeException(e); 1039 + Device device = deviceService.queryDevice(deviceId);
  1040 + if (device == null) {
  1041 + return;
  1042 + }
  1043 +// if (audioBroadcastCatch.getStatus() == AudioBroadcastCatchStatus.Ok) {
  1044 +// cmder.streamByeCmd(device, audioBroadcastCatch.getChannelId(), null, audioBroadcastCatch.getSipTransactionInfo().getCallId());
  1045 +// }
  1046 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null);
  1047 + if (sendRtpItem != null) {
  1048 + redisCatchStorage.deleteSendRTPServer(deviceId, sendRtpItem.getChannelId(), null, null);
  1049 + MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  1050 + Map<String, Object> param = new HashMap<>();
  1051 + param.put("vhost", "__defaultVhost__");
  1052 + param.put("app", sendRtpItem.getApp());
  1053 + param.put("stream", sendRtpItem.getStreamId());
  1054 + zlmresTfulUtils.stopSendRtp(mediaInfo, param);
879 } 1055 }
880 - }  
881 -  
882 1056
  1057 + audioBroadcastManager.del(deviceId, channelId);
  1058 + }
883 } 1059 }
884 1060
885 @Override 1061 @Override
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -216,65 +216,20 @@ public class PlayController { @@ -216,65 +216,20 @@ public class PlayController {
216 @Parameter(name = "timeout", description = "推流超时时间(秒)", required = true) 216 @Parameter(name = "timeout", description = "推流超时时间(秒)", required = true)
217 @GetMapping("/broadcast/{deviceId}/{channelId}") 217 @GetMapping("/broadcast/{deviceId}/{channelId}")
218 @PostMapping("/broadcast/{deviceId}/{channelId}") 218 @PostMapping("/broadcast/{deviceId}/{channelId}")
219 - public DeferredResult<String> broadcastApi(@PathVariable String deviceId, @PathVariable String channelId, Integer timeout) { 219 + public AudioBroadcastResult broadcastApi(@PathVariable String deviceId, @PathVariable String channelId, Integer timeout) {
220 if (logger.isDebugEnabled()) { 220 if (logger.isDebugEnabled()) {
221 logger.debug("语音广播API调用"); 221 logger.debug("语音广播API调用");
222 } 222 }
223 Device device = storager.queryVideoDevice(deviceId); 223 Device device = storager.queryVideoDevice(deviceId);
224 - DeferredResult<String> result = new DeferredResult<>(3 * 1000L);  
225 if (device == null) { 224 if (device == null) {
226 - result.setResult("未找到设备: " + deviceId);  
227 - return result; 225 + throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到设备: " + deviceId);
228 } 226 }
229 if (channelId == null) { 227 if (channelId == null) {
230 - result.setResult("未找到通道: " + channelId);  
231 - return result; 228 + throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到通道: " + channelId);
232 } 229 }
233 - String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId;  
234 - if (resultHolder.exist(key, null)) {  
235 - result.setResult("设备使用中");  
236 - return result;  
237 - }  
238 - if (timeout == null){  
239 - timeout = 30;  
240 - }  
241 - String uuid = UUID.randomUUID().toString();  
242 -  
243 - result.onTimeout(() -> {  
244 - logger.warn("语音广播操作超时, 设备未返回应答指令");  
245 - RequestMessage msg = new RequestMessage();  
246 - msg.setKey(key);  
247 - msg.setId(uuid);  
248 - JSONObject json = new JSONObject();  
249 - json.put("DeviceID", deviceId);  
250 - json.put("CmdType", "Broadcast");  
251 - json.put("Result", "Failed");  
252 - json.put("Error", "Timeout. Device did not response to broadcast command.");  
253 - msg.setData(json);  
254 - resultHolder.invokeResult(msg);  
255 - });  
256 -  
257 - result.onTimeout(()->{  
258 - WVPResult<AudioBroadcastResult> wvpResult = new WVPResult<>();  
259 - wvpResult.setCode(-1);  
260 - wvpResult.setMsg("请求超时");  
261 - RequestMessage requestMessage = new RequestMessage();  
262 - requestMessage.setKey(key);  
263 - requestMessage.setData(wvpResult);  
264 - resultHolder.invokeAllResult(requestMessage);  
265 - });  
266 - playService.audioBroadcast(device, channelId, timeout, (msg)->{  
267 - WVPResult<AudioBroadcastResult> wvpResult = new WVPResult<>();  
268 - wvpResult.setCode(-1);  
269 - wvpResult.setMsg(msg);  
270 - RequestMessage requestMessage = new RequestMessage();  
271 - requestMessage.setKey(key);  
272 - requestMessage.setData(wvpResult);  
273 - resultHolder.invokeAllResult(requestMessage);  
274 - });  
275 - resultHolder.put(key, uuid, result);  
276 -  
277 - return result; 230 +
  231 + return playService.audioBroadcast(device, channelId);
  232 +
278 } 233 }
279 234
280 235
@@ -283,10 +238,16 @@ public class PlayController { @@ -283,10 +238,16 @@ public class PlayController {
283 @Parameter(name = "channelId", description = "通道Id", required = true) 238 @Parameter(name = "channelId", description = "通道Id", required = true)
284 @GetMapping("/broadcast/stop/{deviceId}/{channelId}") 239 @GetMapping("/broadcast/stop/{deviceId}/{channelId}")
285 @PostMapping("/broadcast/stop/{deviceId}/{channelId}") 240 @PostMapping("/broadcast/stop/{deviceId}/{channelId}")
286 - public void stopBroadcastA(@PathVariable String deviceId, @PathVariable String channelId) { 241 + public void stopBroadcast(@PathVariable String deviceId, @PathVariable String channelId) {
287 if (logger.isDebugEnabled()) { 242 if (logger.isDebugEnabled()) {
288 logger.debug("停止语音广播API调用"); 243 logger.debug("停止语音广播API调用");
289 } 244 }
  245 +// try {
  246 +// playService.stopAudioBroadcast(deviceId, channelId);
  247 +// } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) {
  248 +// logger.error("[命令发送失败] 停止语音: {}", e.getMessage());
  249 +// throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
  250 +// }
290 playService.stopAudioBroadcast(deviceId, channelId); 251 playService.stopAudioBroadcast(deviceId, channelId);
291 } 252 }
292 253
web_src/config/index.js
@@ -12,14 +12,14 @@ module.exports = { @@ -12,14 +12,14 @@ module.exports = {
12 assetsPublicPath: '/', 12 assetsPublicPath: '/',
13 proxyTable: { 13 proxyTable: {
14 '/debug': { 14 '/debug': {
15 - target: 'http://localhost:38080', 15 + target: 'https://default.wvp-pro.cn:18080',
16 changeOrigin: true, 16 changeOrigin: true,
17 pathRewrite: { 17 pathRewrite: {
18 '^/debug': '/' 18 '^/debug': '/'
19 } 19 }
20 }, 20 },
21 '/static/snap': { 21 '/static/snap': {
22 - target: 'http://localhost:38080', 22 + target: 'https://default.wvp-pro.cn:18080',
23 changeOrigin: true, 23 changeOrigin: true,
24 // pathRewrite: { 24 // pathRewrite: {
25 // '^/static/snap': '/static/snap' 25 // '^/static/snap': '/static/snap'
web_src/src/components/dialog/devicePlayer.vue
1 <template> 1 <template>
2 <div id="devicePlayer" v-loading="isLoging"> 2 <div id="devicePlayer" v-loading="isLoging">
3 3
4 - <el-dialog title="视频播放" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="close()"> 4 + <el-dialog title="视频播放" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" @close="close()">
5 <!-- <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></LivePlayer> --> 5 <!-- <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></LivePlayer> -->
6 <div style="width: 100%; height: 100%"> 6 <div style="width: 100%; height: 100%">
7 <el-tabs type="card" :stretch="true" v-model="activePlayer" @tab-click="changePlayer" v-if="Object.keys(this.player).length > 1"> 7 <el-tabs type="card" :stretch="true" v-model="activePlayer" @tab-click="changePlayer" v-if="Object.keys(this.player).length > 1">
@@ -119,6 +119,10 @@ @@ -119,6 +119,10 @@
119 <el-tag >RTC:</el-tag> 119 <el-tag >RTC:</el-tag>
120 <span>{{ streamInfo.rtc }}</span> 120 <span>{{ streamInfo.rtc }}</span>
121 </el-dropdown-item> 121 </el-dropdown-item>
  122 + <el-dropdown-item :command="streamInfo.rtcs">
  123 + <el-tag >RTCS:</el-tag>
  124 + <span>{{ streamInfo.rtcs }}</span>
  125 + </el-dropdown-item>
122 <el-dropdown-item :command="streamInfo.rtmp"> 126 <el-dropdown-item :command="streamInfo.rtmp">
123 <el-tag >RTMP:</el-tag> 127 <el-tag >RTMP:</el-tag>
124 <span>{{ streamInfo.rtmp }}</span> 128 <span>{{ streamInfo.rtmp }}</span>
@@ -875,7 +879,8 @@ export default { @@ -875,7 +879,8 @@ export default {
875 } 879 }
876 }); 880 });
877 }else if (this.broadcastStatus === 1) { 881 }else if (this.broadcastStatus === 1) {
878 - this.stopBroadcast() 882 + this.broadcastStatus = -1;
  883 + this.broadcastRtc.close()
879 } 884 }
880 }, 885 },
881 startBroadcast(url){ 886 startBroadcast(url){
@@ -890,6 +895,7 @@ export default { @@ -890,6 +895,7 @@ export default {
890 message: "获取推流鉴权Key失败", 895 message: "获取推流鉴权Key失败",
891 type: "error", 896 type: "error",
892 }); 897 });
  898 + this.broadcastStatus = -1;
893 }else { 899 }else {
894 let pushKey = res.data.data.pushKey; 900 let pushKey = res.data.data.pushKey;
895 // 获取推流鉴权KEY 901 // 获取推流鉴权KEY
@@ -923,6 +929,7 @@ export default { @@ -923,6 +929,7 @@ export default {
923 message: '不支持webrtc, 无法进行语音对讲', 929 message: '不支持webrtc, 无法进行语音对讲',
924 type: 'error' 930 type: 'error'
925 }); 931 });
  932 + this.broadcastStatus = -1;
926 }); 933 });
927 934
928 this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE 协商出错 935 this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE 协商出错
@@ -932,6 +939,7 @@ export default { @@ -932,6 +939,7 @@ export default {
932 message: 'ICE 协商出错', 939 message: 'ICE 协商出错',
933 type: 'error' 940 type: 'error'
934 }); 941 });
  942 + this.broadcastStatus = -1;
935 }); 943 });
936 944
937 this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,(e)=>{// offer anwser 交换失败 945 this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,(e)=>{// offer anwser 交换失败
@@ -941,6 +949,7 @@ export default { @@ -941,6 +949,7 @@ export default {
941 message: 'offer anwser 交换失败' + e, 949 message: 'offer anwser 交换失败' + e,
942 type: 'error' 950 type: 'error'
943 }); 951 });
  952 + this.broadcastStatus = -1;
944 }); 953 });
945 this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE,(e)=>{// offer anwser 交换失败 954 this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE,(e)=>{// offer anwser 交换失败
946 console.log('状态改变',e) 955 console.log('状态改变',e)
@@ -959,36 +968,38 @@ export default { @@ -959,36 +968,38 @@ export default {
959 message: '捕获流失败' + e, 968 message: '捕获流失败' + e,
960 type: 'error' 969 type: 'error'
961 }); 970 });
  971 + this.broadcastStatus = -1;
962 }); 972 });
963 } 973 }
  974 + }).catch((e) => {
  975 + this.$message({
  976 + showClose: true,
  977 + message: e,
  978 + type: 'error'
  979 + });
  980 + this.broadcastStatus = -1;
964 }); 981 });
965 982
966 983
967 }, 984 },
968 stopBroadcast(){ 985 stopBroadcast(){
969 - if (this.broadcastStatus === -1) {  
970 - this.broadcastStatus = 1;  
971 - }else {  
972 - this.broadcastStatus = -2;  
973 - this.broadcastRtc = null;  
974 - this.$axios({  
975 - method: 'get',  
976 - url: '/api/play/broadcast/stop/' + this.deviceId + '/' + this.channelId  
977 - }).then( (res)=> {  
978 - if (res.data.code == 0) {  
979 - // this.broadcastStatus = -1;  
980 - // this.broadcastRtc.close()  
981 - }else {  
982 - this.$message({  
983 - showClose: true,  
984 - message: res.data.msg,  
985 - type: "error",  
986 - });  
987 - }  
988 - });  
989 - }  
990 -  
991 - 986 + this.broadcastRtc.close();
  987 + this.broadcastStatus = -1;
  988 + this.$axios({
  989 + method: 'get',
  990 + url: '/api/play/broadcast/stop/' + this.deviceId + '/' + this.channelId
  991 + }).then( (res)=> {
  992 + if (res.data.code == 0) {
  993 + // this.broadcastStatus = -1;
  994 + // this.broadcastRtc.close()
  995 + }else {
  996 + this.$message({
  997 + showClose: true,
  998 + message: res.data.msg,
  999 + type: "error",
  1000 + });
  1001 + }
  1002 + });
992 } 1003 }
993 } 1004 }
994 }; 1005 };