Commit 039fbf7e243d4bf0f46b44e7dae2a5d36e978056

Authored by 648540858
2 parents ebe24a6c a000ed60

Merge branch 'talk' into main-dev

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
#	src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
Showing 27 changed files with 427 additions and 337 deletions
src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
@@ -63,6 +63,8 @@ public class AudioBroadcastCatch { @@ -63,6 +63,8 @@ public class AudioBroadcastCatch {
63 */ 63 */
64 private SipTransactionInfo sipTransactionInfo; 64 private SipTransactionInfo sipTransactionInfo;
65 65
  66 + private MediaServerItem mediaServerItem;
  67 +
66 68
67 public String getDeviceId() { 69 public String getDeviceId() {
68 return deviceId; 70 return deviceId;
@@ -123,4 +125,12 @@ public class AudioBroadcastCatch { @@ -123,4 +125,12 @@ public class AudioBroadcastCatch {
123 public void setSipTransactionInfoByRequset(SIPResponse response) { 125 public void setSipTransactionInfoByRequset(SIPResponse response) {
124 this.sipTransactionInfo = new SipTransactionInfo(response, false); 126 this.sipTransactionInfo = new SipTransactionInfo(response, false);
125 } 127 }
  128 +
  129 + public MediaServerItem getMediaServerItem() {
  130 + return mediaServerItem;
  131 + }
  132 +
  133 + public void setMediaServerItem(MediaServerItem mediaServerItem) {
  134 + this.mediaServerItem = mediaServerItem;
  135 + }
126 } 136 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
@@ -49,7 +49,7 @@ public class SendRtpItem { @@ -49,7 +49,7 @@ public class SendRtpItem {
49 /** 49 /**
50 * 设备推流的streamId 50 * 设备推流的streamId
51 */ 51 */
52 - private String streamId; 52 + private String stream;
53 53
54 /** 54 /**
55 * 是否为tcp 55 * 是否为tcp
@@ -117,6 +117,11 @@ public class SendRtpItem { @@ -117,6 +117,11 @@ public class SendRtpItem {
117 */ 117 */
118 private InviteStreamType playType; 118 private InviteStreamType playType;
119 119
  120 + /**
  121 + * 发流的同时收流
  122 + */
  123 + private String receiveStream;
  124 +
120 public String getIp() { 125 public String getIp() {
121 return ip; 126 return ip;
122 } 127 }
@@ -181,12 +186,12 @@ public class SendRtpItem { @@ -181,12 +186,12 @@ public class SendRtpItem {
181 this.app = app; 186 this.app = app;
182 } 187 }
183 188
184 - public String getStreamId() {  
185 - return streamId; 189 + public String getStream() {
  190 + return stream;
186 } 191 }
187 192
188 - public void setStreamId(String streamId) {  
189 - this.streamId = streamId; 193 + public void setStream(String stream) {
  194 + this.stream = stream;
190 } 195 }
191 196
192 public boolean isTcp() { 197 public boolean isTcp() {
@@ -292,4 +297,12 @@ public class SendRtpItem { @@ -292,4 +297,12 @@ public class SendRtpItem {
292 public void setRtcp(boolean rtcp) { 297 public void setRtcp(boolean rtcp) {
293 this.rtcp = rtcp; 298 this.rtcp = rtcp;
294 } 299 }
  300 +
  301 + public String getReceiveStream() {
  302 + return receiveStream;
  303 + }
  304 +
  305 + public void setReceiveStream(String receiveStream) {
  306 + this.receiveStream = receiveStream;
  307 + }
295 } 308 }
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;  
4 import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent; 3 import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent;
5 import gov.nist.javax.sip.message.SIPRequest; 4 import gov.nist.javax.sip.message.SIPRequest;
6 import org.slf4j.Logger; 5 import org.slf4j.Logger;
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
@@ -29,7 +29,8 @@ public class VideoStreamSessionManager { @@ -29,7 +29,8 @@ public class VideoStreamSessionManager {
29 play, 29 play,
30 playback, 30 playback,
31 download, 31 download,
32 - broadcast 32 + broadcast,
  33 + talk
33 } 34 }
34 35
35 /** 36 /**
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
@@ -94,12 +94,12 @@ public class SipRunner implements CommandLineRunner { @@ -94,12 +94,12 @@ public class SipRunner implements CommandLineRunner {
94 if (sendRtpItems.size() > 0) { 94 if (sendRtpItems.size() > 0) {
95 for (SendRtpItem sendRtpItem : sendRtpItems) { 95 for (SendRtpItem sendRtpItem : sendRtpItems) {
96 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId()); 96 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
97 - redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStreamId()); 97 + redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStream());
98 if (mediaServerItem != null) { 98 if (mediaServerItem != null) {
99 Map<String, Object> param = new HashMap<>(); 99 Map<String, Object> param = new HashMap<>();
100 param.put("vhost","__defaultVhost__"); 100 param.put("vhost","__defaultVhost__");
101 param.put("app",sendRtpItem.getApp()); 101 param.put("app",sendRtpItem.getApp());
102 - param.put("stream",sendRtpItem.getStreamId()); 102 + param.put("stream",sendRtpItem.getStream());
103 param.put("ssrc",sendRtpItem.getSsrc()); 103 param.put("ssrc",sendRtpItem.getSsrc());
104 JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param); 104 JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
105 if (jsonObject != null && jsonObject.getInteger("code") == 0) { 105 if (jsonObject != null && jsonObject.getInteger("code") == 0) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -2,10 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd; @@ -2,10 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
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.DeviceAlarm;  
7 -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;  
8 -import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; 5 +import com.genersoft.iot.vmp.gb28181.bean.*;
9 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 6 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
10 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 7 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 8 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -131,7 +128,7 @@ public interface ISIPCommander { @@ -131,7 +128,7 @@ public interface ISIPCommander {
131 */ 128 */
132 void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; 129 void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
133 130
134 - 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; 131 + void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
135 132
136 133
137 void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException; 134 void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -32,7 +32,6 @@ import org.springframework.beans.factory.annotation.Autowired; @@ -32,7 +32,6 @@ import org.springframework.beans.factory.annotation.Autowired;
32 import org.springframework.context.annotation.DependsOn; 32 import org.springframework.context.annotation.DependsOn;
33 import org.springframework.stereotype.Component; 33 import org.springframework.stereotype.Component;
34 import org.springframework.util.ObjectUtils; 34 import org.springframework.util.ObjectUtils;
35 -import org.springframework.util.StringUtils;  
36 35
37 import javax.sip.InvalidArgumentException; 36 import javax.sip.InvalidArgumentException;
38 import javax.sip.ResponseEvent; 37 import javax.sip.ResponseEvent;
@@ -584,9 +583,9 @@ public class SIPCommander implements ISIPCommander { @@ -584,9 +583,9 @@ public class SIPCommander implements ISIPCommander {
584 } 583 }
585 584
586 @Override 585 @Override
587 - 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 { 586 + public void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
588 587
589 - String stream = ssrcInfo.getStream(); 588 + String stream = sendRtpItem.getStream();
590 589
591 if (device == null) { 590 if (device == null) {
592 return; 591 return;
@@ -597,7 +596,7 @@ public class SIPCommander implements ISIPCommander { @@ -597,7 +596,7 @@ public class SIPCommander implements ISIPCommander {
597 return; 596 return;
598 } 597 }
599 598
600 - logger.info("[语音对讲] {} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); 599 + logger.info("[语音对讲] {} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), sendRtpItem.getPort());
601 HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); 600 HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
602 subscribe.addSubscribe(hookSubscribeForStreamChange, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { 601 subscribe.addSubscribe(hookSubscribeForStreamChange, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
603 if (event != null) { 602 if (event != null) {
@@ -622,24 +621,27 @@ public class SIPCommander implements ISIPCommander { @@ -622,24 +621,27 @@ public class SIPCommander implements ISIPCommander {
622 content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); 621 content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
623 content.append("t=0 0\r\n"); 622 content.append("t=0 0\r\n");
624 623
625 - content.append("m=audio " + ssrcInfo.getPort() + " RTP/AVP 8\r\n"); 624 + content.append("m=audio " + sendRtpItem.getPort() + " TCP/RTP/AVP 8\r\n");
  625 + content.append("a=setup:passive\r\n");
  626 + content.append("a=connection:new\r\n");
626 content.append("a=sendrecv\r\n"); 627 content.append("a=sendrecv\r\n");
627 content.append("a=rtpmap:8 PCMA/8000\r\n"); 628 content.append("a=rtpmap:8 PCMA/8000\r\n");
628 629
629 - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc 630 + content.append("y=" + sendRtpItem.getSsrc() + "\r\n");//ssrc
630 // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 631 // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
631 content.append("f=v/////a/1/8/1" + "\r\n"); 632 content.append("f=v/////a/1/8/1" + "\r\n");
632 633
633 - Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(), callIdHeader); 634 + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(),
  635 + SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sendRtpItem.getSsrc(), callIdHeader);
634 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> { 636 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
635 - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());  
636 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); 637 + streamSession.remove(device.getDeviceId(), channelId, sendRtpItem.getStream());
  638 + mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
637 errorEvent.response(e); 639 errorEvent.response(e);
638 }), e -> { 640 }), e -> {
639 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 641 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
640 ResponseEvent responseEvent = (ResponseEvent) e.event; 642 ResponseEvent responseEvent = (ResponseEvent) e.event;
641 SIPResponse response = (SIPResponse) responseEvent.getResponse(); 643 SIPResponse response = (SIPResponse) responseEvent.getResponse();
642 - streamSession.put(device.getDeviceId(), channelId, "talk", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.play); 644 + streamSession.put(device.getDeviceId(), channelId, "talk", stream, sendRtpItem.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.talk);
643 okEvent.response(e); 645 okEvent.response(e);
644 }); 646 });
645 } 647 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -694,7 +694,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -694,7 +694,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
694 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); 694 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
695 if (mediaServerItem != null) { 695 if (mediaServerItem != null) {
696 mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc()); 696 mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
697 - zlmrtpServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStreamId()); 697 + zlmrtpServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStream());
698 } 698 }
699 SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(platform, sendRtpItem); 699 SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(platform, sendRtpItem);
700 if (byeRequest == null) { 700 if (byeRequest == null) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -102,12 +102,12 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -102,12 +102,12 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
102 } 102 }
103 String isUdp = sendRtpItem.isTcp() ? "0" : "1"; 103 String isUdp = sendRtpItem.isTcp() ? "0" : "1";
104 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); 104 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
105 - logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStreamId(), 105 + logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
106 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp()); 106 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
107 Map<String, Object> param = new HashMap<>(12); 107 Map<String, Object> param = new HashMap<>(12);
108 param.put("vhost","__defaultVhost__"); 108 param.put("vhost","__defaultVhost__");
109 param.put("app",sendRtpItem.getApp()); 109 param.put("app",sendRtpItem.getApp());
110 - param.put("stream",sendRtpItem.getStreamId()); 110 + param.put("stream",sendRtpItem.getStream());
111 param.put("ssrc", sendRtpItem.getSsrc()); 111 param.put("ssrc", sendRtpItem.getSsrc());
112 param.put("src_port", sendRtpItem.getLocalPort()); 112 param.put("src_port", sendRtpItem.getLocalPort());
113 param.put("pt", sendRtpItem.getPt()); 113 param.put("pt", sendRtpItem.getPt());
@@ -121,7 +121,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -121,7 +121,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
121 121
122 if (mediaInfo == null) { 122 if (mediaInfo == null) {
123 RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance( 123 RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
124 - sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(), 124 + sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStream(),
125 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(), 125 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
126 sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio()); 126 sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
127 redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> { 127 redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
@@ -97,7 +97,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -97,7 +97,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
97 97
98 if (sendRtpItem != null){ 98 if (sendRtpItem != null){
99 logger.info("[收到bye] {}/{}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId()); 99 logger.info("[收到bye] {}/{}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId());
100 - String streamId = sendRtpItem.getStreamId(); 100 + String streamId = sendRtpItem.getStream();
101 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId()); 101 MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
102 if (mediaServerItem == null) { 102 if (mediaServerItem == null) {
103 return; 103 return;
@@ -105,7 +105,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -105,7 +105,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
105 105
106 Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItem, sendRtpItem.getApp(), streamId); 106 Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItem, sendRtpItem.getApp(), streamId);
107 if (!ready) { 107 if (!ready) {
108 - logger.info("[收到bye] 发现流{}/{}已经结束,不需处理", sendRtpItem.getApp(), sendRtpItem.getStreamId()); 108 + logger.info("[收到bye] 发现流{}/{}已经结束,不需处理", sendRtpItem.getApp(), sendRtpItem.getStream());
109 return; 109 return;
110 } 110 }
111 Map<String, Object> param = new HashMap<>(); 111 Map<String, Object> param = new HashMap<>();
@@ -113,7 +113,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -113,7 +113,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
113 param.put("app",sendRtpItem.getApp()); 113 param.put("app",sendRtpItem.getApp());
114 param.put("stream",streamId); 114 param.put("stream",streamId);
115 param.put("ssrc",sendRtpItem.getSsrc()); 115 param.put("ssrc",sendRtpItem.getSsrc());
116 - logger.info("[收到bye] 停止向上级推流:{}", streamId); 116 + logger.info("[收到bye] 停止推流:{}", streamId);
117 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); 117 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
118 redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), callIdHeader.getCallId(), null); 118 redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), callIdHeader.getCallId(), null);
119 zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); 119 zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
@@ -129,15 +129,14 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -129,15 +129,14 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
129 try { 129 try {
130 logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); 130 logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
131 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null); 131 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null);
132 - } catch (InvalidArgumentException | ParseException | SipException |  
133 - SsrcTransactionNotFoundException e) { 132 + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
134 logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); 133 logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage());
135 } 134 }
136 } 135 }
137 136
138 if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) { 137 if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) {
139 MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, 138 MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
140 - sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), 139 + sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(),
141 sendRtpItem.getPlatformId(), null, null, sendRtpItem.getMediaServerId()); 140 sendRtpItem.getPlatformId(), null, null, sendRtpItem.getMediaServerId());
142 redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel); 141 redisCatchStorage.sendStreamPushRequestedMsg(messageForPushChannel);
143 } 142 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -478,7 +478,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -478,7 +478,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
478 if ("Playback".equalsIgnoreCase(sessionName)) { 478 if ("Playback".equalsIgnoreCase(sessionName)) {
479 sendRtpItem.setPlayType(InviteStreamType.PLAYBACK); 479 sendRtpItem.setPlayType(InviteStreamType.PLAYBACK);
480 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, device.isSsrcCheck(), true); 480 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, device.isSsrcCheck(), true);
481 - sendRtpItem.setStreamId(ssrcInfo.getStream()); 481 + sendRtpItem.setStream(ssrcInfo.getStream());
482 // 写入redis, 超时时回复 482 // 写入redis, 超时时回复
483 redisCatchStorage.updateSendRTPSever(sendRtpItem); 483 redisCatchStorage.updateSendRTPSever(sendRtpItem);
484 playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), 484 playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
@@ -523,7 +523,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -523,7 +523,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
523 } 523 }
524 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false); 524 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false);
525 logger.info(JSONObject.toJSONString(ssrcInfo)); 525 logger.info(JSONObject.toJSONString(ssrcInfo));
526 - sendRtpItem.setStreamId(ssrcInfo.getStream()); 526 + sendRtpItem.setStream(ssrcInfo.getStream());
527 sendRtpItem.setSsrc(ssrc.equals(ssrcDefault) ? ssrcInfo.getSsrc() : ssrc); 527 sendRtpItem.setSsrc(ssrc.equals(ssrcDefault) ? ssrcInfo.getSsrc() : ssrc);
528 528
529 // 写入redis, 超时时回复 529 // 写入redis, 超时时回复
@@ -533,12 +533,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -533,12 +533,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
533 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), finalChannelId, callIdHeader.getCallId(), null); 533 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), finalChannelId, callIdHeader.getCallId(), null);
534 }); 534 });
535 } else { 535 } else {
536 - sendRtpItem.setStreamId(playTransaction.getStream()); 536 + sendRtpItem.setStream(playTransaction.getStream());
537 // 写入redis, 超时时回复 537 // 写入redis, 超时时回复
538 redisCatchStorage.updateSendRTPSever(sendRtpItem); 538 redisCatchStorage.updateSendRTPSever(sendRtpItem);
539 JSONObject jsonObject = new JSONObject(); 539 JSONObject jsonObject = new JSONObject();
540 jsonObject.put("app", sendRtpItem.getApp()); 540 jsonObject.put("app", sendRtpItem.getApp());
541 - jsonObject.put("stream", sendRtpItem.getStreamId()); 541 + jsonObject.put("stream", sendRtpItem.getStream());
542 hookEvent.response(mediaServerItem, jsonObject); 542 hookEvent.response(mediaServerItem, jsonObject);
543 } 543 }
544 } 544 }
@@ -982,6 +982,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -982,6 +982,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
982 } 982 }
983 return; 983 return;
984 } 984 }
  985 + String addressStr = sdp.getOrigin().getAddress();
  986 + logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc,
  987 + mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP");
  988 +
  989 + MediaServerItem mediaServerItem = audioBroadcastCatch.getMediaServerItem();
  990 + if (mediaServerItem == null) {
  991 + logger.warn("未找到语音喊话使用的zlm");
  992 + try {
  993 + responseAck(request, Response.BUSY_HERE);
  994 + } catch (SipException | InvalidArgumentException | ParseException e) {
  995 + logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage());
  996 + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  997 + }
  998 + return;
  999 + }
985 String addressStr = sdp.getConnection().getAddress(); 1000 String addressStr = sdp.getConnection().getAddress();
986 logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, ssrc, 1001 logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, ssrc,
987 mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP", sdp.getSessionName().getValue()); 1002 mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP", sdp.getSessionName().getValue());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java
@@ -102,7 +102,7 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I @@ -102,7 +102,7 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I
102 String contentSubType = header.getContentSubType(); 102 String contentSubType = header.getContentSubType();
103 if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) { 103 if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) {
104 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); 104 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
105 - String streamId = sendRtpItem.getStreamId(); 105 + String streamId = sendRtpItem.getStream();
106 StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); 106 StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
107 if (null == streamInfo) { 107 if (null == streamInfo) {
108 responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found"); 108 responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found");
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
@@ -90,7 +90,7 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -90,7 +90,7 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
90 90
91 try { 91 try {
92 cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); 92 cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId());
93 - } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) { 93 + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
94 logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage()); 94 logger.error("[录像流]推送完毕,收到关流通知, 发送BYE失败 {}", e.getMessage());
95 } 95 }
96 96
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
@@ -123,7 +123,7 @@ public class SipUtils { @@ -123,7 +123,7 @@ public class SipUtils {
123 } 123 }
124 124
125 public static String getNewCallId() { 125 public static String getNewCallId() {
126 - return (int) Math.floor(Math.random() * 10000) + ""; 126 + return (int) Math.floor(Math.random() * 1000000000) + "";
127 } 127 }
128 128
129 public static int getTypeCodeFromGbCode(String deviceId) { 129 public static int getTypeCodeFromGbCode(String deviceId) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -9,9 +9,9 @@ import com.genersoft.iot.vmp.gb28181.bean.*; @@ -9,9 +9,9 @@ import com.genersoft.iot.vmp.gb28181.bean.*;
9 import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 9 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
10 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; 10 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
11 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 11 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
12 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;  
13 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 12 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
14 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 13 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  14 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
15 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 15 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
16 import com.genersoft.iot.vmp.media.zlm.dto.HookType; 16 import com.genersoft.iot.vmp.media.zlm.dto.HookType;
17 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 17 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -249,6 +249,7 @@ public class ZLMHttpHookListener { @@ -249,6 +249,7 @@ public class ZLMHttpHookListener {
249 String channelId = ssrcTransactionForAll.get(0).getChannelId(); 249 String channelId = ssrcTransactionForAll.get(0).getChannelId();
250 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); 250 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
251 if (deviceChannel != null) { 251 if (deviceChannel != null) {
  252 +
252 result.setEnable_audio(deviceChannel.isHasAudio()); 253 result.setEnable_audio(deviceChannel.isHasAudio());
253 } 254 }
254 // 如果是录像下载就设置视频间隔十秒 255 // 如果是录像下载就设置视频间隔十秒
@@ -257,6 +258,11 @@ public class ZLMHttpHookListener { @@ -257,6 +258,11 @@ public class ZLMHttpHookListener {
257 result.setEnable_audio(true); 258 result.setEnable_audio(true);
258 result.setEnable_mp4(true); 259 result.setEnable_mp4(true);
259 } 260 }
  261 + // 如果是talk对讲,则默认获取声音
  262 + if (ssrcTransactionForAll.get(0).getType() == VideoStreamSessionManager.SessionType.talk) {
  263 + result.setEnable_audio(true);
  264 + }
  265 +
260 } 266 }
261 return result; 267 return result;
262 } 268 }
@@ -359,62 +365,30 @@ public class ZLMHttpHookListener { @@ -359,62 +365,30 @@ public class ZLMHttpHookListener {
359 } 365 }
360 }else if ("talk".equals(param.getApp())){ 366 }else if ("talk".equals(param.getApp())){
361 // 语音对讲推流 stream需要满足格式deviceId_channelId 367 // 语音对讲推流 stream需要满足格式deviceId_channelId
362 - if (param.isRegist() && param.getStream().indexOf("_") > 0) {  
363 - String[] streamArray = param.getStream().split("_");  
364 - if (streamArray.length == 2) {  
365 - String deviceId = streamArray[0];  
366 - String channelId = streamArray[1];  
367 - Device device = deviceService.getDevice(deviceId);  
368 - if (device != null) {  
369 - DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);  
370 - if (deviceChannel != null) {  
371 - if (audioBroadcastManager.exit(deviceId, channelId)) {  
372 - // 直接推流  
373 - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, param.getStream(), null);  
374 - if (sendRtpItem == null) {  
375 - // TODO 可能数据错误,重新开启语音通道  
376 - }else {  
377 - MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());  
378 - logger.info("rtp/{}开始向上级推流, 目标={}:{},SSRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());  
379 - Map<String, Object> sendParam = new HashMap<>(12);  
380 - sendParam.put("vhost","__defaultVhost__");  
381 - sendParam.put("app",sendRtpItem.getApp());  
382 - sendParam.put("stream",sendRtpItem.getStreamId());  
383 - sendParam.put("ssrc", sendRtpItem.getSsrc());  
384 - sendParam.put("src_port", sendRtpItem.getLocalPort());  
385 - sendParam.put("pt", sendRtpItem.getPt());  
386 - sendParam.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");  
387 - sendParam.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");  
388 -  
389 - JSONObject jsonObject;  
390 - if (sendRtpItem.isTcpActive()) {  
391 - jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaServerItem, sendParam);  
392 - } else {  
393 - sendParam.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");  
394 - sendParam.put("dst_url", sendRtpItem.getIp());  
395 - sendParam.put("dst_port", sendRtpItem.getPort());  
396 - jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaServerItem, sendParam);  
397 - }  
398 - if (jsonObject != null && jsonObject.getInteger("code") == 0) {  
399 - logger.info("[语音对讲] 自动推流成功, device: {}, channel: {}", deviceId, channelId);  
400 - }  
401 - }  
402 - }else {  
403 - // 开启语音对讲通道  
404 - MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());  
405 - playService.talk(mediaServerItem, device, channelId, (mediaServer, jsonObject)->{  
406 - System.out.println("开始推流");  
407 - }, eventResult -> {  
408 - System.out.println(eventResult.msg);  
409 - }, ()->{  
410 - System.out.println("超时");  
411 - });  
412 - }  
413 -  
414 - }  
415 - }  
416 - }  
417 - } 368 + if (param.getStream().indexOf("_") > 0) {
  369 + String[] streamArray = param.getStream().split("_");
  370 + if (streamArray.length == 2) {
  371 + String deviceId = streamArray[0];
  372 + String channelId = streamArray[1];
  373 + Device device = deviceService.getDevice(deviceId);
  374 + if (device != null) {
  375 + if (param.isRegist()) {
  376 + if (audioBroadcastManager.exit(deviceId, channelId)) {
  377 + playService.stopAudioBroadcast(deviceId, channelId);
  378 + }
  379 + // 开启语音对讲通道
  380 + playService.talkCmd(device, channelId, mediaInfo, param.getStream(), (msg)->{
  381 + logger.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId);
  382 + });
  383 + }else {
  384 + // 流注销
  385 + playService.stopTalk(device, channelId, param.isRegist());
  386 + }
  387 + } else{
  388 + logger.info("[语音对讲] 未找到设备:{}", deviceId);
  389 + }
  390 + }
  391 + }
418 392
419 }else{ 393 }else{
420 if (!"rtp".equals(param.getApp())){ 394 if (!"rtp".equals(param.getApp())){
@@ -474,16 +448,21 @@ public class ZLMHttpHookListener { @@ -474,16 +448,21 @@ public class ZLMHttpHookListener {
474 ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); 448 ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
475 Device device = deviceService.getDevice(platformId); 449 Device device = deviceService.getDevice(platformId);
476 450
477 - try { 451 +
478 if (platform != null) { 452 if (platform != null) {
479 - commanderFroPlatform.streamByeCmd(platform, sendRtpItem); 453 + try {
  454 + commanderFroPlatform.streamByeCmd(platform, sendRtpItem);
  455 + } catch (SipException | InvalidArgumentException | ParseException e) {
  456 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  457 + }
480 } else { 458 } else {
481 - cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); 459 + try {
  460 + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId());
  461 + } catch (SipException | InvalidArgumentException | ParseException |
  462 + SsrcTransactionNotFoundException e) {
  463 + logger.error("[命令发送失败] 发送BYE: {}", e.getMessage());
  464 + }
482 } 465 }
483 - } catch (SipException | InvalidArgumentException | ParseException |  
484 - SsrcTransactionNotFoundException e) {  
485 - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());  
486 - }  
487 } 466 }
488 } 467 }
489 } 468 }
@@ -526,7 +505,7 @@ public class ZLMHttpHookListener { @@ -526,7 +505,7 @@ public class ZLMHttpHookListener {
526 logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); 505 logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
527 } 506 }
528 redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), 507 redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
529 - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); 508 + sendRtpItem.getCallId(), sendRtpItem.getStream());
530 } 509 }
531 } 510 }
532 } 511 }
@@ -555,8 +534,7 @@ public class ZLMHttpHookListener { @@ -555,8 +534,7 @@ public class ZLMHttpHookListener {
555 try { 534 try {
556 cmder.streamByeCmd(device, streamInfoForPlayBackCatch.getChannelId(), 535 cmder.streamByeCmd(device, streamInfoForPlayBackCatch.getChannelId(),
557 streamInfoForPlayBackCatch.getStream(), null); 536 streamInfoForPlayBackCatch.getStream(), null);
558 - } catch (InvalidArgumentException | ParseException | SipException |  
559 - SsrcTransactionNotFoundException e) { 537 + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
560 logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage()); 538 logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage());
561 } 539 }
562 } 540 }
@@ -572,6 +550,13 @@ public class ZLMHttpHookListener { @@ -572,6 +550,13 @@ public class ZLMHttpHookListener {
572 ret.put("close", false); 550 ret.put("close", false);
573 return ret; 551 return ret;
574 } 552 }
  553 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, param.getStream(), null);
  554 + if ("talk".equals(sendRtpItem.getApp())){
  555 + ret.put("close", false);
  556 + return ret;
  557 + }
  558 + }else if ("talk".equals(param.getApp()) || "broadcast".equals(param.getApp())){
  559 + ret.put("close", false);
575 } else { 560 } else {
576 // 非国标流 推流/拉流代理 561 // 非国标流 推流/拉流代理
577 // 拉流代理 562 // 拉流代理
@@ -733,7 +718,7 @@ public class ZLMHttpHookListener { @@ -733,7 +718,7 @@ public class ZLMHttpHookListener {
733 logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); 718 logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
734 } 719 }
735 redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(), 720 redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
736 - sendRtpItem.getCallId(), sendRtpItem.getStreamId()); 721 + sendRtpItem.getCallId(), sendRtpItem.getStream());
737 } 722 }
738 } 723 }
739 }); 724 });
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -291,6 +291,10 @@ public class ZLMRESTfulUtils { @@ -291,6 +291,10 @@ public class ZLMRESTfulUtils {
291 return sendPost(mediaServerItem, "startSendRtpPassive",param, null); 291 return sendPost(mediaServerItem, "startSendRtpPassive",param, null);
292 } 292 }
293 293
  294 + public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object> param, RequestCallback callback) {
  295 + return sendPost(mediaServerItem, "startSendRtpPassive",param, callback);
  296 + }
  297 +
294 public JSONObject stopSendRtp(MediaServerItem mediaServerItem, Map<String, Object> param) { 298 public JSONObject stopSendRtp(MediaServerItem mediaServerItem, Map<String, Object> param) {
295 return sendPost(mediaServerItem, "stopSendRtp",param, null); 299 return sendPost(mediaServerItem, "stopSendRtp",param, null);
296 } 300 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -229,7 +229,7 @@ public class ZLMRTPServerFactory { @@ -229,7 +229,7 @@ public class ZLMRTPServerFactory {
229 sendRtpItem.setPort(port); 229 sendRtpItem.setPort(port);
230 sendRtpItem.setSsrc(ssrc); 230 sendRtpItem.setSsrc(ssrc);
231 sendRtpItem.setApp(app); 231 sendRtpItem.setApp(app);
232 - sendRtpItem.setStreamId(stream); 232 + sendRtpItem.setStream(stream);
233 sendRtpItem.setPlatformId(platformId); 233 sendRtpItem.setPlatformId(platformId);
234 sendRtpItem.setChannelId(channelId); 234 sendRtpItem.setChannelId(channelId);
235 sendRtpItem.setTcp(tcp); 235 sendRtpItem.setTcp(tcp);
@@ -290,6 +290,10 @@ public class ZLMRTPServerFactory { @@ -290,6 +290,10 @@ public class ZLMRTPServerFactory {
290 return zlmresTfulUtils.startSendRtpPassive(mediaServerItem, param); 290 return zlmresTfulUtils.startSendRtpPassive(mediaServerItem, param);
291 } 291 }
292 292
  293 + public JSONObject startSendRtpPassive(MediaServerItem mediaServerItem, Map<String, Object>param, ZLMRESTfulUtils.RequestCallback callback) {
  294 + return zlmresTfulUtils.startSendRtpPassive(mediaServerItem, param, callback);
  295 + }
  296 +
293 /** 297 /**
294 * 查询待转推的流是否就绪 298 * 查询待转推的流是否就绪
295 */ 299 */
@@ -343,7 +347,7 @@ public class ZLMRTPServerFactory { @@ -343,7 +347,7 @@ public class ZLMRTPServerFactory {
343 result= true; 347 result= true;
344 logger.info("[停止RTP推流] 成功"); 348 logger.info("[停止RTP推流] 成功");
345 } else { 349 } else {
346 - logger.error("[停止RTP推流] 失败: {}, 参数:{}->\r\n{}",jsonObject.getString("msg"), JSON.toJSON(param), jsonObject); 350 + logger.warn("[停止RTP推流] 失败: {}, 参数:{}->\r\n{}",jsonObject.getString("msg"), JSON.toJSON(param), jsonObject);
347 } 351 }
348 return result; 352 return result;
349 } 353 }
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.service.bean.PlayBackCallback; @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
12 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 12 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
13 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; 13 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
14 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; 14 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
  15 +import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioEvent;
15 import gov.nist.javax.sip.message.SIPResponse; 16 import gov.nist.javax.sip.message.SIPResponse;
16 17
17 import javax.sip.InvalidArgumentException; 18 import javax.sip.InvalidArgumentException;
@@ -27,10 +28,6 @@ public interface IPlayService { @@ -27,10 +28,6 @@ public interface IPlayService {
27 28
28 void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId); 29 void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId);
29 30
30 - void talk(MediaServerItem mediaServerItem, Device device, String channelId,  
31 - ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,  
32 - Runnable timeoutCallback);  
33 -  
34 void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 31 void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
35 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, 32 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
36 InviteTimeOutCallback timeoutCallback); 33 InviteTimeOutCallback timeoutCallback);
@@ -57,7 +54,7 @@ public interface IPlayService { @@ -57,7 +54,7 @@ public interface IPlayService {
57 54
58 void zlmServerOnline(String mediaServerId); 55 void zlmServerOnline(String mediaServerId);
59 56
60 - AudioBroadcastResult audioBroadcast(Device device, String channelId); 57 + AudioBroadcastResult audioBroadcast(Device device, String channelId, Boolean broadcastMode);
61 void stopAudioBroadcast(String deviceId, String channelId); 58 void stopAudioBroadcast(String deviceId, String channelId);
62 59
63 void audioBroadcastCmd(Device device, String channelId, int timeout, MediaServerItem mediaServerItem, String sourceApp, String sourceStream, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException; 60 void audioBroadcastCmd(Device device, String channelId, int timeout, MediaServerItem mediaServerItem, String sourceApp, String sourceStream, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
@@ -70,4 +67,8 @@ public interface IPlayService { @@ -70,4 +67,8 @@ public interface IPlayService {
70 67
71 void startSendRtpStreamHand(SendRtpItem sendRtpItem, ParentPlatform parentPlatform, 68 void startSendRtpStreamHand(SendRtpItem sendRtpItem, ParentPlatform parentPlatform,
72 JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader); 69 JSONObject jsonObject, Map<String, Object> param, CallIdHeader callIdHeader);
  70 +
  71 + void talkCmd(Device device, String channelId, MediaServerItem mediaServerItem, String stream, AudioEvent event);
  72 +
  73 + void stopTalk(Device device, String channelId, Boolean streamIsReady);
73 } 74 }
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -202,7 +202,7 @@ public class DeviceServiceImpl implements IDeviceService { @@ -202,7 +202,7 @@ public class DeviceServiceImpl implements IDeviceService {
202 Map<String, Object> param = new HashMap<>(); 202 Map<String, Object> param = new HashMap<>();
203 param.put("vhost", "__defaultVhost__"); 203 param.put("vhost", "__defaultVhost__");
204 param.put("app", sendRtpItem.getApp()); 204 param.put("app", sendRtpItem.getApp());
205 - param.put("stream", sendRtpItem.getStreamId()); 205 + param.put("stream", sendRtpItem.getStream());
206 zlmresTfulUtils.stopSendRtp(mediaInfo, param); 206 zlmresTfulUtils.stopSendRtp(mediaInfo, param);
207 } 207 }
208 208
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
@@ -253,7 +253,7 @@ public class PlatformServiceImpl implements IPlatformService { @@ -253,7 +253,7 @@ public class PlatformServiceImpl implements IPlatformService {
253 Map<String, Object> param = new HashMap<>(3); 253 Map<String, Object> param = new HashMap<>(3);
254 param.put("vhost", "__defaultVhost__"); 254 param.put("vhost", "__defaultVhost__");
255 param.put("app", sendRtpItem.getApp()); 255 param.put("app", sendRtpItem.getApp());
256 - param.put("stream", sendRtpItem.getStreamId()); 256 + param.put("stream", sendRtpItem.getStream());
257 zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); 257 zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
258 } 258 }
259 } 259 }
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -41,7 +41,7 @@ import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; @@ -41,7 +41,7 @@ import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
41 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 41 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
42 import com.genersoft.iot.vmp.vmanager.bean.StreamContent; 42 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
43 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 43 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
44 -import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; 44 +import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioEvent;
45 import gov.nist.javax.sip.message.SIPResponse; 45 import gov.nist.javax.sip.message.SIPResponse;
46 import org.slf4j.Logger; 46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory; 47 import org.slf4j.LoggerFactory;
@@ -134,8 +134,8 @@ public class PlayServiceImpl implements IPlayService { @@ -134,8 +134,8 @@ public class PlayServiceImpl implements IPlayService {
134 134
135 @Override 135 @Override
136 public void play(MediaServerItem mediaServerItem, String deviceId, String channelId, 136 public void play(MediaServerItem mediaServerItem, String deviceId, String channelId,
137 - ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,  
138 - Runnable timeoutCallback) { 137 + ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
  138 + Runnable timeoutCallback) {
139 if (mediaServerItem == null) { 139 if (mediaServerItem == null) {
140 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm"); 140 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm");
141 } 141 }
@@ -243,194 +243,148 @@ public class PlayServiceImpl implements IPlayService { @@ -243,194 +243,148 @@ public class PlayServiceImpl implements IPlayService {
243 } 243 }
244 } 244 }
245 245
246 - @Override  
247 - public void talk(MediaServerItem mediaServerItem, Device device, String channelId,  
248 - ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,  
249 - Runnable timeoutCallback) {  
250 - String streamId = null;  
251 - if (mediaServerItem.isRtpEnable()) {  
252 - streamId = String.format("%s_%s", device.getDeviceId(), channelId); 246 + private void talk(MediaServerItem mediaServerItem, Device device, String channelId, String stream,
  247 + ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
  248 + Runnable timeoutCallback, AudioEvent audioEvent) {
  249 +
  250 + String playSsrc = mediaServerItem.getSsrcConfig().getPlaySsrc();
  251 + if (playSsrc == null) {
  252 + audioEvent.call("ssrc已经用尽");
  253 + return;
  254 + }
  255 + SendRtpItem sendRtpItem = new SendRtpItem();
  256 + sendRtpItem.setApp("talk");
  257 + sendRtpItem.setStream(stream);
  258 + sendRtpItem.setSsrc(playSsrc);
  259 + sendRtpItem.setDeviceId(device.getDeviceId());
  260 + sendRtpItem.setPlatformId(device.getDeviceId());
  261 + sendRtpItem.setChannelId(channelId);
  262 + sendRtpItem.setRtcp(false);
  263 + sendRtpItem.setMediaServerId(mediaServerItem.getId());
  264 + sendRtpItem.setOnlyAudio(true);
  265 + sendRtpItem.setPlayType(InviteStreamType.TALK);
  266 + sendRtpItem.setPt(8);
  267 + sendRtpItem.setStatus(1);
  268 + sendRtpItem.setTcpActive(false);
  269 + sendRtpItem.setTcp(true);
  270 + sendRtpItem.setUsePs(false);
  271 + sendRtpItem.setReceiveStream(stream + "_talk");
  272 +
  273 +
  274 + int port = zlmrtpServerFactory.keepPort(mediaServerItem, playSsrc);
  275 + //端口获取失败的ssrcInfo 没有必要发送点播指令
  276 + if (port <= 0) {
  277 + logger.info("[语音对讲] 端口分配异常,deviceId={},channelId={}", device.getDeviceId(), channelId);
  278 + audioEvent.call("端口分配异常");
  279 + return;
253 } 280 }
254 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);  
255 - logger.info("[对讲开始] deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); 281 + sendRtpItem.setLocalPort(port);
  282 + sendRtpItem.setPort(port);
  283 + logger.info("[语音对讲]开始 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sendRtpItem.getLocalPort(), device.getStreamMode(), sendRtpItem.getSsrc(), false);
256 // 超时处理 284 // 超时处理
257 String timeOutTaskKey = UUID.randomUUID().toString(); 285 String timeOutTaskKey = UUID.randomUUID().toString();
258 - SSRCInfo finalSsrcInfo = ssrcInfo;  
259 - System.out.println("设置超时任务: " + timeOutTaskKey);  
260 dynamicTask.startDelay(timeOutTaskKey, () -> { 286 dynamicTask.startDelay(timeOutTaskKey, () -> {
261 287
262 - logger.info("[对讲超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, finalSsrcInfo.getPort(), finalSsrcInfo.getSsrc()); 288 + logger.info("[语音对讲] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, sendRtpItem.getPort(), sendRtpItem.getSsrc());
263 timeoutCallback.run(); 289 timeoutCallback.run();
264 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 290 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
265 try { 291 try {
266 - cmder.streamByeCmd(device, channelId, finalSsrcInfo.getStream(), null);  
267 - } catch (InvalidArgumentException | ParseException | SipException e) {  
268 - logger.error("[对讲超时], 发送BYE失败 {}", e.getMessage());  
269 - } catch (SsrcTransactionNotFoundException e) { 292 + cmder.streamByeCmd(device, channelId, sendRtpItem.getStream(), null);
  293 + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
  294 + logger.error("[语音对讲]超时, 发送BYE失败 {}", e.getMessage());
  295 + } finally {
270 timeoutCallback.run(); 296 timeoutCallback.run();
271 - mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());  
272 - mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());  
273 - streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); 297 + mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
  298 + streamSession.remove(device.getDeviceId(), channelId, sendRtpItem.getStream());
274 } 299 }
275 }, userSetting.getPlayTimeout()); 300 }, userSetting.getPlayTimeout());
276 - final String ssrc = ssrcInfo.getSsrc();  
277 - final String stream = ssrcInfo.getStream();  
278 - //端口获取失败的ssrcInfo 没有必要发送点播指令  
279 - if (ssrcInfo.getPort() <= 0) {  
280 - logger.info("[对讲] 端口分配异常,deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo);  
281 - return;  
282 - }  
283 301
284 String callId = SipUtils.getNewCallId(); 302 String callId = SipUtils.getNewCallId();
285 - boolean pushing = false;  
286 - // 查看设备是否已经在推流  
287 -// MediaItem mediaItem = zlmrtpServerFactory.getMediaInfo(mediaServerItem, "rtp",ssrcInfo.getStream());  
288 -// if (mediaItem != null) {  
289 -// SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem,  
290 -// mediaItem.getOriginSock().getPeer_ip(), mediaItem.getOriginSock().getPeer_port(), ssrcInfo.getSsrc(), device.getDeviceId(),  
291 -// device.getDeviceId(), channelId,  
292 -// false);  
293 -//  
294 -// sendRtpItem.setTcpActive(false);  
295 -// sendRtpItem.setCallId(callId);  
296 -// sendRtpItem.setPlayType(InviteStreamType.TALK);  
297 -// sendRtpItem.setStatus(1);  
298 -// sendRtpItem.setIp(mediaItem.getOriginSock().getPeer_ip());  
299 -// sendRtpItem.setPort(mediaItem.getOriginSock().getPeer_port());  
300 -// sendRtpItem.setTcpActive(false);  
301 -// sendRtpItem.setStreamId(ssrcInfo.getStream());  
302 -// sendRtpItem.setApp("1000");  
303 -// sendRtpItem.setStreamId("1000");  
304 -// sendRtpItem.setSsrc(ssrc);  
305 -// sendRtpItem.setOnlyAudio(true);  
306 -// redisCatchStorage.updateSendRTPSever(sendRtpItem);  
307 -//  
308 -// Map<String, Object> param = new HashMap<>(12);  
309 -// param.put("vhost","__defaultVhost__");  
310 -// param.put("app",sendRtpItem.getApp());  
311 -// param.put("stream",sendRtpItem.getStreamId());  
312 -// param.put("ssrc", sendRtpItem.getSsrc());  
313 -// param.put("dst_url", sendRtpItem.getIp());  
314 -// param.put("dst_port", sendRtpItem.getPort());  
315 -// param.put("src_port", sendRtpItem.getLocalPort());  
316 -// param.put("pt", sendRtpItem.getPt());  
317 -// param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");  
318 -// param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");  
319 -// param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");  
320 -// JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaServerItem, param);  
321 -// System.out.println(2222);  
322 -// System.out.println(jsonObject);  
323 -// }else {  
324 - try {  
325 - cmder.talkStreamCmd(mediaServerItem, ssrcInfo, device, channelId, callId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {  
326 - logger.info("[对讲] 流已生成, 开始推流: " + response.toJSONString());  
327 - dynamicTask.stop(timeOutTaskKey);  
328 - // TODO 暂不做处理  
329 - }, (MediaServerItem mediaServerItemInuse, JSONObject json) -> {  
330 - logger.info("[对讲] 设备开始推流: " + json.toJSONString());  
331 - dynamicTask.stop(timeOutTaskKey);  
332 - // 获取远程IP端口 作为回复语音流的地址  
333 - String ip = json.getString("ip");  
334 - Integer port = json.getInteger("port");  
335 - logger.info("[设备开始推流]{}/{}, 来自ip:{}, 端口:{}", device.getDeviceId(), channelId, ip, port);  
336 - // 查看平台推流是否就绪  
337 -// Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItemInuse, "talk", stream);  
338 -// if (!ready) {  
339 -// try {  
340 -// cmder.streamByeCmd(device, channelId, finalSsrcInfo.getStream(), null);  
341 -// } catch (InvalidArgumentException | ParseException | SipException e) {  
342 -// logger.error("[对讲超时], 发送BYE失败 {}", e.getMessage());  
343 -// } catch (SsrcTransactionNotFoundException e) {  
344 -// timeoutCallback.run();  
345 -// mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());  
346 -// mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());  
347 -// streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());  
348 -// }  
349 -// }else {  
350 -// try {  
351 -// Thread.sleep(1000);  
352 -// } catch (InterruptedException e) {  
353 -// throw new RuntimeException(e);  
354 -// }  
355 - SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, ip, port, ssrcInfo.getSsrc(), device.getDeviceId(),  
356 - device.getDeviceId(), channelId,  
357 - false, false);  
358 -  
359 -  
360 -// if (sendRtpItem.getLocalPort() == 0) {  
361 -// logger.warn("服务器端口资源不足");  
362 -// try {  
363 -// cmder.streamByeCmd(device, channelId, finalSsrcInfo.getStream(), null);  
364 -// } catch (InvalidArgumentException | ParseException | SipException e) {  
365 -// logger.error("[对讲超时], 发送BYE失败 {}", e.getMessage());  
366 -// } catch (SsrcTransactionNotFoundException e) {  
367 -// timeoutCallback.run();  
368 -// mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());  
369 -// mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());  
370 -// streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());  
371 -// }  
372 -// return;  
373 -// }  
374 - sendRtpItem.setTcpActive(false);  
375 - sendRtpItem.setCallId(callId);  
376 - sendRtpItem.setPlayType(InviteStreamType.TALK);  
377 - sendRtpItem.setStatus(1);  
378 - sendRtpItem.setIp(ip);  
379 - sendRtpItem.setPort(port);  
380 - sendRtpItem.setTcpActive(false);  
381 - sendRtpItem.setApp("1000");  
382 - sendRtpItem.setStreamId("1000");  
383 - sendRtpItem.setSsrc(ssrc);  
384 - sendRtpItem.setOnlyAudio(true);  
385 - sendRtpItem.setRtcp(false);  
386 - redisCatchStorage.updateSendRTPSever(sendRtpItem);  
387 303
388 - Map<String, Object> param = new HashMap<>(12);  
389 - param.put("vhost","__defaultVhost__");  
390 - param.put("app",sendRtpItem.getApp());  
391 - param.put("stream",sendRtpItem.getStreamId());  
392 - param.put("ssrc", sendRtpItem.getSsrc());  
393 - param.put("dst_url", sendRtpItem.getIp());  
394 - param.put("dst_port", sendRtpItem.getPort());  
395 - param.put("src_port", sendRtpItem.getLocalPort());  
396 - param.put("pt", sendRtpItem.getPt());  
397 - param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");  
398 - param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");  
399 - param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");  
400 - JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaServerItemInuse, param);  
401 - System.out.println(11111);  
402 - System.out.println(sendRtpItem.getIp() + ":" + sendRtpItem.getPort());  
403 -// System.out.println(jsonObject);  
404 -// } 304 + zlmrtpServerFactory.releasePort(mediaServerItem, playSsrc);
  305 + Map<String, Object> param = new HashMap<>(12);
  306 + param.put("vhost","__defaultVhost__");
  307 + param.put("app", sendRtpItem.getApp());
  308 + param.put("stream", sendRtpItem.getStream());
  309 + param.put("ssrc", sendRtpItem.getSsrc());
  310 + param.put("src_port", sendRtpItem.getLocalPort());
  311 + param.put("pt", sendRtpItem.getPt());
  312 + param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  313 + param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  314 + param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
  315 + param.put("recv_stream_id", sendRtpItem.getReceiveStream());
  316 + param.put("close_delay_ms", userSetting.getPlayTimeout() * 1000);
  317 +
  318 + zlmrtpServerFactory.startSendRtpPassive(mediaServerItem, param, jsonObject -> {
  319 + if (jsonObject == null || jsonObject.getInteger("code") != 0 ) {
  320 + mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
  321 + logger.info("[语音对讲]失败 deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
  322 + audioEvent.call("失败, " + jsonObject.getString("msg"));
  323 + // 查看是否已经建立了通道,存在则发送bye
  324 + stopTalk(device, channelId);
  325 + }
  326 + });
405 327
406 - }, (event) -> {  
407 328
408 - }, (event) -> {  
409 - dynamicTask.stop(timeOutTaskKey);  
410 - mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream());  
411 - // 释放ssrc  
412 - mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); 329 + // 查看设备是否已经在推流
  330 + try {
  331 + cmder.talkStreamCmd(mediaServerItem, sendRtpItem, device, channelId, callId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
  332 + logger.info("[语音对讲] 流已生成, 开始推流: " + response.toJSONString());
  333 + dynamicTask.stop(timeOutTaskKey);
  334 + // TODO 暂不做处理
  335 + }, (MediaServerItem mediaServerItemInuse, JSONObject json) -> {
  336 + logger.info("[语音对讲] 设备开始推流: " + json.toJSONString());
  337 + dynamicTask.stop(timeOutTaskKey);
  338 +
  339 + }, (event) -> {
  340 + dynamicTask.stop(timeOutTaskKey);
413 341
414 - streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());  
415 - errorEvent.response(event);  
416 - });  
417 - } catch (InvalidArgumentException | SipException | ParseException e) { 342 + if (event.event instanceof ResponseEvent) {
  343 + ResponseEvent responseEvent = (ResponseEvent) event.event;
  344 + if (responseEvent.getResponse() instanceof SIPResponse) {
  345 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  346 + sendRtpItem.setFromTag(response.getFromTag());
  347 + sendRtpItem.setToTag(response.getToTag());
  348 + sendRtpItem.setCallId(response.getCallIdHeader().getCallId());
  349 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
418 350
419 - logger.error("[命令发送失败] 对讲消息: {}", e.getMessage()); 351 + streamSession.put(device.getDeviceId(), channelId, "talk",
  352 + sendRtpItem.getStream(), sendRtpItem.getSsrc(), sendRtpItem.getMediaServerId(),
  353 + response, VideoStreamSessionManager.SessionType.talk);
  354 + } else {
  355 + logger.error("[语音对讲]收到的消息错误,response不是SIPResponse");
  356 + }
  357 + } else {
  358 + logger.error("[语音对讲]收到的消息错误,event不是ResponseEvent");
  359 + }
  360 +
  361 + }, (event) -> {
420 dynamicTask.stop(timeOutTaskKey); 362 dynamicTask.stop(timeOutTaskKey);
421 - mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream()); 363 + mediaServerService.closeRTPServer(mediaServerItem, sendRtpItem.getStream());
422 // 释放ssrc 364 // 释放ssrc
423 - mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); 365 + mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
  366 + streamSession.remove(device.getDeviceId(), channelId, sendRtpItem.getStream());
  367 + errorEvent.response(event);
  368 + });
  369 + } catch (InvalidArgumentException | SipException | ParseException e) {
424 370
425 - streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());  
426 - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null));  
427 - eventResult.msg = "命令发送失败";  
428 - errorEvent.response(eventResult);  
429 - } 371 + logger.error("[命令发送失败] 对讲消息: {}", e.getMessage());
  372 + dynamicTask.stop(timeOutTaskKey);
  373 + mediaServerService.closeRTPServer(mediaServerItem, sendRtpItem.getStream());
  374 + // 释放ssrc
  375 + mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
  376 +
  377 + streamSession.remove(device.getDeviceId(), channelId, sendRtpItem.getStream());
  378 + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new CmdSendFailEvent(null));
  379 + eventResult.msg = "命令发送失败";
  380 + errorEvent.response(eventResult);
  381 + }
430 // } 382 // }
431 383
432 } 384 }
433 385
  386 +
  387 +
434 @Override 388 @Override
435 public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 389 public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
436 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, 390 ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
@@ -446,7 +400,8 @@ public class PlayServiceImpl implements IPlayService { @@ -446,7 +400,8 @@ public class PlayServiceImpl implements IPlayService {
446 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 400 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
447 try { 401 try {
448 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); 402 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null);
449 - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { 403 + } catch (InvalidArgumentException | ParseException | SipException |
  404 + SsrcTransactionNotFoundException e) {
450 logger.error("[点播超时], 发送BYE失败 {}", e.getMessage()); 405 logger.error("[点播超时], 发送BYE失败 {}", e.getMessage());
451 } finally { 406 } finally {
452 timeoutCallback.run(1, "收流超时"); 407 timeoutCallback.run(1, "收流超时");
@@ -483,7 +438,7 @@ public class PlayServiceImpl implements IPlayService { @@ -483,7 +438,7 @@ public class PlayServiceImpl implements IPlayService {
483 onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId); 438 onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId);
484 hookEvent.response(mediaServerItemInuse, response); 439 hookEvent.response(mediaServerItemInuse, response);
485 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); 440 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
486 - String streamUrl = String.format("http://127.0.0.1:%s/%s/%s.live.flv", mediaServerItemInuse.getHttpPort(), "rtp", ssrcInfo.getStream()); 441 + String streamUrl = String.format("http://127.0.0.1:%s/%s/%s.live.flv", mediaServerItemInuse.getHttpPort(), "rtp", ssrcInfo.getStream());
487 String path = "snap"; 442 String path = "snap";
488 String fileName = device.getDeviceId() + "_" + channelId + ".jpg"; 443 String fileName = device.getDeviceId() + "_" + channelId + ".jpg";
489 // 请求截图 444 // 请求截图
@@ -652,8 +607,8 @@ public class PlayServiceImpl implements IPlayService { @@ -652,8 +607,8 @@ public class PlayServiceImpl implements IPlayService {
652 607
653 @Override 608 @Override
654 public void playBack(String deviceId, String channelId, String startTime, 609 public void playBack(String deviceId, String channelId, String startTime,
655 - String endTime, InviteStreamCallback inviteStreamCallback,  
656 - PlayBackCallback callback) { 610 + String endTime, InviteStreamCallback inviteStreamCallback,
  611 + PlayBackCallback callback) {
657 Device device = storager.queryVideoDevice(deviceId); 612 Device device = storager.queryVideoDevice(deviceId);
658 if (device == null) { 613 if (device == null) {
659 return; 614 return;
@@ -666,9 +621,9 @@ public class PlayServiceImpl implements IPlayService { @@ -666,9 +621,9 @@ public class PlayServiceImpl implements IPlayService {
666 621
667 @Override 622 @Override
668 public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, 623 public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
669 - String deviceId, String channelId, String startTime,  
670 - String endTime, InviteStreamCallback infoCallBack,  
671 - PlayBackCallback playBackCallback) { 624 + String deviceId, String channelId, String startTime,
  625 + String endTime, InviteStreamCallback infoCallBack,
  626 + PlayBackCallback playBackCallback) {
672 if (mediaServerItem == null || ssrcInfo == null) { 627 if (mediaServerItem == null || ssrcInfo == null) {
673 return; 628 return;
674 } 629 }
@@ -792,7 +747,6 @@ public class PlayServiceImpl implements IPlayService { @@ -792,7 +747,6 @@ public class PlayServiceImpl implements IPlayService {
792 } 747 }
793 748
794 749
795 -  
796 @Override 750 @Override
797 public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback) { 751 public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback) {
798 Device device = storager.queryVideoDevice(deviceId); 752 Device device = storager.queryVideoDevice(deviceId);
@@ -977,7 +931,7 @@ public class PlayServiceImpl implements IPlayService { @@ -977,7 +931,7 @@ public class PlayServiceImpl implements IPlayService {
977 cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), 931 cmder.streamByeCmd(device, ssrcTransaction.getChannelId(),
978 ssrcTransaction.getStream(), null); 932 ssrcTransaction.getStream(), null);
979 } catch (InvalidArgumentException | ParseException | SipException | 933 } catch (InvalidArgumentException | ParseException | SipException |
980 - SsrcTransactionNotFoundException e) { 934 + SsrcTransactionNotFoundException e) {
981 logger.error("[zlm离线]为正在使用此zlm的设备, 发送BYE失败 {}", e.getMessage()); 935 logger.error("[zlm离线]为正在使用此zlm的设备, 发送BYE失败 {}", e.getMessage());
982 } 936 }
983 } 937 }
@@ -986,7 +940,8 @@ public class PlayServiceImpl implements IPlayService { @@ -986,7 +940,8 @@ public class PlayServiceImpl implements IPlayService {
986 } 940 }
987 941
988 @Override 942 @Override
989 - public AudioBroadcastResult audioBroadcast(Device device, String channelId) { 943 + public AudioBroadcastResult audioBroadcast(Device device, String channelId, Boolean broadcastMode) {
  944 + // TODO 必须多端口模式才支持语音喊话鹤语音对讲
990 if (device == null || channelId == null) { 945 if (device == null || channelId == null) {
991 return null; 946 return null;
992 } 947 }
@@ -997,15 +952,15 @@ public class PlayServiceImpl implements IPlayService { @@ -997,15 +952,15 @@ public class PlayServiceImpl implements IPlayService {
997 return null; 952 return null;
998 } 953 }
999 MediaServerItem mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(null); 954 MediaServerItem mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(null);
1000 - String app = "broadcast";  
1001 - // TODO 从sip user agent中判断是什么品牌设备,大华默认使用talk模式,其他使用broadcast模式  
1002 -// String app = "talk"; 955 + if (broadcastMode == null) {
  956 + broadcastMode = true;
  957 + }
  958 + String app = broadcastMode?"broadcast":"talk";
1003 String stream = device.getDeviceId() + "_" + channelId; 959 String stream = device.getDeviceId() + "_" + channelId;
1004 - StreamInfo broadcast = mediaService.getStreamInfoByAppAndStream(mediaServerItem, "broadcast", stream, null, null, null, false);  
1005 AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult(); 960 AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult();
1006 audioBroadcastResult.setApp(app); 961 audioBroadcastResult.setApp(app);
1007 audioBroadcastResult.setStream(stream); 962 audioBroadcastResult.setStream(stream);
1008 - audioBroadcastResult.setStreamInfo(new StreamContent(mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, stream, null, null, null,false))); 963 + audioBroadcastResult.setStreamInfo(new StreamContent(mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, stream, null, null, null, false)));
1009 audioBroadcastResult.setCodec("G.711"); 964 audioBroadcastResult.setCodec("G.711");
1010 return audioBroadcastResult; 965 return audioBroadcastResult;
1011 } 966 }
@@ -1037,6 +992,18 @@ public class PlayServiceImpl implements IPlayService { @@ -1037,6 +992,18 @@ public class PlayServiceImpl implements IPlayService {
1037 } 992 }
1038 } 993 }
1039 } 994 }
  995 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
  996 + if (sendRtpItem != null) {
  997 + MediaServerItem mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  998 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServer, "rtp", sendRtpItem.getReceiveStream());
  999 + if (streamReady) {
  1000 + logger.warn("[语音对讲] 进行中: {}", channelId);
  1001 + event.call("语音对讲进行中");
  1002 + return;
  1003 + } else {
  1004 + stopTalk(device, channelId);
  1005 + }
  1006 + }
1040 1007
1041 // 发送通知 1008 // 发送通知
1042 cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> { 1009 cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> {
@@ -1053,19 +1020,18 @@ public class PlayServiceImpl implements IPlayService { @@ -1053,19 +1020,18 @@ public class PlayServiceImpl implements IPlayService {
1053 } 1020 }
1054 1021
1055 1022
1056 -  
1057 @Override 1023 @Override
1058 public void stopAudioBroadcast(String deviceId, String channelId) { 1024 public void stopAudioBroadcast(String deviceId, String channelId) {
1059 List<AudioBroadcastCatch> audioBroadcastCatchList = new ArrayList<>(); 1025 List<AudioBroadcastCatch> audioBroadcastCatchList = new ArrayList<>();
1060 if (channelId == null) { 1026 if (channelId == null) {
1061 audioBroadcastCatchList.addAll(audioBroadcastManager.get(deviceId)); 1027 audioBroadcastCatchList.addAll(audioBroadcastManager.get(deviceId));
1062 - }else { 1028 + } else {
1063 audioBroadcastCatchList.add(audioBroadcastManager.get(deviceId, channelId)); 1029 audioBroadcastCatchList.add(audioBroadcastManager.get(deviceId, channelId));
1064 } 1030 }
1065 if (audioBroadcastCatchList.size() > 0) { 1031 if (audioBroadcastCatchList.size() > 0) {
1066 for (AudioBroadcastCatch audioBroadcastCatch : audioBroadcastCatchList) { 1032 for (AudioBroadcastCatch audioBroadcastCatch : audioBroadcastCatchList) {
1067 Device device = deviceService.getDevice(deviceId); 1033 Device device = deviceService.getDevice(deviceId);
1068 - if (device == null || audioBroadcastCatch == null ) { 1034 + if (device == null || audioBroadcastCatch == null) {
1069 return; 1035 return;
1070 } 1036 }
1071 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null); 1037 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null);
@@ -1075,7 +1041,7 @@ public class PlayServiceImpl implements IPlayService { @@ -1075,7 +1041,7 @@ public class PlayServiceImpl implements IPlayService {
1075 Map<String, Object> param = new HashMap<>(); 1041 Map<String, Object> param = new HashMap<>();
1076 param.put("vhost", "__defaultVhost__"); 1042 param.put("vhost", "__defaultVhost__");
1077 param.put("app", sendRtpItem.getApp()); 1043 param.put("app", sendRtpItem.getApp());
1078 - param.put("stream", sendRtpItem.getStreamId()); 1044 + param.put("stream", sendRtpItem.getStream());
1079 zlmresTfulUtils.stopSendRtp(mediaInfo, param); 1045 zlmresTfulUtils.stopSendRtp(mediaInfo, param);
1080 try { 1046 try {
1081 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null); 1047 cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null);
@@ -1199,12 +1165,12 @@ public class PlayServiceImpl implements IPlayService { @@ -1199,12 +1165,12 @@ public class PlayServiceImpl implements IPlayService {
1199 1165
1200 String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; 1166 String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
1201 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); 1167 MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
1202 - logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStreamId(), 1168 + logger.info("收到ACK,rtp/{}开始向上级推流, 目标={}:{},SSRC={}, RTCP={}", sendRtpItem.getStream(),
1203 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp()); 1169 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp());
1204 Map<String, Object> param = new HashMap<>(12); 1170 Map<String, Object> param = new HashMap<>(12);
1205 - param.put("vhost","__defaultVhost__");  
1206 - param.put("app",sendRtpItem.getApp());  
1207 - param.put("stream",sendRtpItem.getStreamId()); 1171 + param.put("vhost", "__defaultVhost__");
  1172 + param.put("app", sendRtpItem.getApp());
  1173 + param.put("stream", sendRtpItem.getStream());
1208 param.put("ssrc", sendRtpItem.getSsrc()); 1174 param.put("ssrc", sendRtpItem.getSsrc());
1209 param.put("src_port", sendRtpItem.getLocalPort()); 1175 param.put("src_port", sendRtpItem.getLocalPort());
1210 param.put("pt", sendRtpItem.getPt()); 1176 param.put("pt", sendRtpItem.getPt());
@@ -1213,12 +1179,12 @@ public class PlayServiceImpl implements IPlayService { @@ -1213,12 +1179,12 @@ public class PlayServiceImpl implements IPlayService {
1213 param.put("is_udp", is_Udp); 1179 param.put("is_udp", is_Udp);
1214 if (!sendRtpItem.isTcp()) { 1180 if (!sendRtpItem.isTcp()) {
1215 // udp模式下开启rtcp保活 1181 // udp模式下开启rtcp保活
1216 - param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0"); 1182 + param.put("udp_rtcp_timeout", sendRtpItem.isRtcp() ? "1" : "0");
1217 } 1183 }
1218 1184
1219 if (mediaInfo == null) { 1185 if (mediaInfo == null) {
1220 RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance( 1186 RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
1221 - sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(), 1187 + sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStream(),
1222 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(), 1188 sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(),
1223 sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio()); 1189 sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio());
1224 redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> { 1190 redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> {
@@ -1233,16 +1199,16 @@ public class PlayServiceImpl implements IPlayService { @@ -1233,16 +1199,16 @@ public class PlayServiceImpl implements IPlayService {
1233 if (zlmrtpServerFactory.releasePort(mediaInfo, sendRtpItem.getSsrc())) { 1199 if (zlmrtpServerFactory.releasePort(mediaInfo, sendRtpItem.getSsrc())) {
1234 if (sendRtpItem.isTcpActive()) { 1200 if (sendRtpItem.isTcpActive()) {
1235 startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param); 1201 startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
1236 - }else { 1202 + } else {
1237 param.put("dst_url", sendRtpItem.getIp()); 1203 param.put("dst_url", sendRtpItem.getIp());
1238 param.put("dst_port", sendRtpItem.getPort()); 1204 param.put("dst_port", sendRtpItem.getPort());
1239 startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); 1205 startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
1240 } 1206 }
1241 } 1207 }
1242 - }else { 1208 + } else {
1243 if (sendRtpItem.isTcpActive()) { 1209 if (sendRtpItem.isTcpActive()) {
1244 startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param); 1210 startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
1245 - }else { 1211 + } else {
1246 param.put("dst_url", sendRtpItem.getIp()); 1212 param.put("dst_url", sendRtpItem.getIp());
1247 param.put("dst_port", sendRtpItem.getPort()); 1213 param.put("dst_port", sendRtpItem.getPort());
1248 startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); 1214 startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
@@ -1260,10 +1226,10 @@ public class PlayServiceImpl implements IPlayService { @@ -1260,10 +1226,10 @@ public class PlayServiceImpl implements IPlayService {
1260 if (jsonObject == null) { 1226 if (jsonObject == null) {
1261 logger.error("RTP推流失败: 请检查ZLM服务"); 1227 logger.error("RTP推流失败: 请检查ZLM服务");
1262 } else if (jsonObject.getInteger("code") == 0) { 1228 } else if (jsonObject.getInteger("code") == 0) {
1263 - logger.info("调用ZLM推流接口, 结果: {}", jsonObject);  
1264 - logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, " ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port")); 1229 + logger.info("调用ZLM推流接口, 结果: {}", jsonObject);
  1230 + logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, ", param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
1265 } else { 1231 } else {
1266 - logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"), JSON.toJSONString(param)); 1232 + logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSON.toJSONString(param));
1267 if (sendRtpItem.isOnlyAudio()) { 1233 if (sendRtpItem.isOnlyAudio()) {
1268 Device device = deviceService.getDevice(sendRtpItem.getDeviceId()); 1234 Device device = deviceService.getDevice(sendRtpItem.getDeviceId());
1269 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); 1235 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId());
@@ -1275,7 +1241,7 @@ public class PlayServiceImpl implements IPlayService { @@ -1275,7 +1241,7 @@ public class PlayServiceImpl implements IPlayService {
1275 logger.error("[命令发送失败] 停止语音对讲: {}", e.getMessage()); 1241 logger.error("[命令发送失败] 停止语音对讲: {}", e.getMessage());
1276 } 1242 }
1277 } 1243 }
1278 - }else { 1244 + } else {
1279 // 向上级平台 1245 // 向上级平台
1280 try { 1246 try {
1281 commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId()); 1247 commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
@@ -1285,4 +1251,105 @@ public class PlayServiceImpl implements IPlayService { @@ -1285,4 +1251,105 @@ public class PlayServiceImpl implements IPlayService {
1285 } 1251 }
1286 } 1252 }
1287 } 1253 }
  1254 +
  1255 + @Override
  1256 + public void talkCmd(Device device, String channelId, MediaServerItem mediaServerItem, String stream, AudioEvent event) {
  1257 + if (device == null || channelId == null) {
  1258 + return;
  1259 + }
  1260 + // TODO 必须多端口模式才支持语音喊话鹤语音对讲
  1261 + logger.info("[语音对讲] device: {}, channel: {}", device.getDeviceId(), channelId);
  1262 + DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
  1263 + if (deviceChannel == null) {
  1264 + logger.warn("开启语音对讲的时候未找到通道: {}", channelId);
  1265 + event.call("开启语音对讲的时候未找到通道");
  1266 + return;
  1267 + }
  1268 + // 查询通道使用状态
  1269 + if (audioBroadcastManager.exit(device.getDeviceId(), channelId)) {
  1270 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
  1271 + if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) {
  1272 + // 查询流是否存在,不存在则认为是异常状态
  1273 + MediaServerItem mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  1274 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream());
  1275 + if (streamReady) {
  1276 + logger.warn("[语音对讲] 正在语音广播,无法开启语音通话: {}", channelId);
  1277 + event.call("正在语音广播");
  1278 + return;
  1279 + } else {
  1280 + stopAudioBroadcast(device.getDeviceId(), channelId);
  1281 + }
  1282 + }
  1283 + }
  1284 +
  1285 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, stream, null);
  1286 + if (sendRtpItem != null) {
  1287 + MediaServerItem mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  1288 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServer, "rtp", sendRtpItem.getReceiveStream());
  1289 + if (streamReady) {
  1290 + logger.warn("[语音对讲] 进行中: {}", channelId);
  1291 + event.call("语音对讲进行中");
  1292 + return;
  1293 + } else {
  1294 + stopTalk(device, channelId);
  1295 + }
  1296 + }
  1297 +
  1298 + talk(mediaServerItem, device, channelId, stream, (MediaServerItem mediaServerItem1, JSONObject response) -> {
  1299 + logger.info("[语音对讲] 收到设备发来的流");
  1300 + }, eventResult -> {
  1301 + logger.warn("[语音对讲] 失败,{}/{}, 错误码 {} {}", device.getDeviceId(), channelId, eventResult.statusCode, eventResult.msg);
  1302 + event.call("失败,错误码 " + eventResult.statusCode + ", " + eventResult.msg);
  1303 + }, () -> {
  1304 + logger.warn("[语音对讲] 失败,{}/{} 超时", device.getDeviceId(), channelId);
  1305 + event.call("失败,超时 ");
  1306 + stopTalk(device, channelId);
  1307 + }, errorMsg -> {
  1308 + logger.warn("[语音对讲] 失败,{}/{} {}", device.getDeviceId(), channelId, errorMsg);
  1309 + event.call(errorMsg);
  1310 + stopTalk(device, channelId);
  1311 + });
  1312 + }
  1313 +
  1314 + private void stopTalk(Device device, String channelId) {
  1315 + stopTalk(device, channelId, null);
  1316 + }
  1317 +
  1318 + @Override
  1319 + public void stopTalk(Device device, String channelId, Boolean streamIsReady) {
  1320 + logger.info("[语音对讲] 停止, {}/{}", device.getDeviceId(), channelId);
  1321 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
  1322 + if (sendRtpItem == null) {
  1323 + logger.info("[语音对讲] 停止失败, 未找到发送信息,可能已经停止");
  1324 + return;
  1325 + }
  1326 + // 停止向设备推流
  1327 + String mediaServerId = sendRtpItem.getMediaServerId();
  1328 + if (mediaServerId == null) {
  1329 + return;
  1330 + }
  1331 +
  1332 + MediaServerItem mediaServer = mediaServerService.getOne(mediaServerId);
  1333 +
  1334 + if (streamIsReady == null || streamIsReady) {
  1335 + Map<String, Object> param = new HashMap<>();
  1336 + param.put("vhost", "__defaultVhost__");
  1337 + param.put("app", sendRtpItem.getApp());
  1338 + param.put("stream", sendRtpItem.getStream());
  1339 + param.put("ssrc", sendRtpItem.getSsrc());
  1340 + zlmrtpServerFactory.stopSendRtpStream(mediaServer, param);
  1341 + }
  1342 +
  1343 + mediaServer.getSsrcConfig().releaseSsrc(sendRtpItem.getSsrc());
  1344 +
  1345 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, null, sendRtpItem.getStream());
  1346 + if (ssrcTransaction != null) {
  1347 + try {
  1348 + cmder.streamByeCmd(device, channelId, sendRtpItem.getStream(), null);
  1349 + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
  1350 + logger.info("[语音对讲] 停止消息发送失败,可能已经停止");
  1351 + }
  1352 + }
  1353 + redisCatchStorage.deleteSendRTPServer(device.getDeviceId(), channelId,null, null);
  1354 + }
1288 } 1355 }
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -378,7 +378,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -378,7 +378,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
378 + sendRtpItem.getMediaServerId() + "_" 378 + sendRtpItem.getMediaServerId() + "_"
379 + sendRtpItem.getPlatformId() + "_" 379 + sendRtpItem.getPlatformId() + "_"
380 + sendRtpItem.getChannelId() + "_" 380 + sendRtpItem.getChannelId() + "_"
381 - + sendRtpItem.getStreamId() + "_" 381 + + sendRtpItem.getStream() + "_"
382 + sendRtpItem.getCallId(); 382 + sendRtpItem.getCallId();
383 RedisUtil.set(key, sendRtpItem); 383 RedisUtil.set(key, sendRtpItem);
384 } 384 }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -19,11 +19,7 @@ import com.genersoft.iot.vmp.service.IMediaService; @@ -19,11 +19,7 @@ import com.genersoft.iot.vmp.service.IMediaService;
19 import com.genersoft.iot.vmp.service.IPlayService; 19 import com.genersoft.iot.vmp.service.IPlayService;
20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
21 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 21 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
22 -import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx;  
23 -import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;  
24 -import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;  
25 -import com.genersoft.iot.vmp.vmanager.bean.StreamContent;  
26 -import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 22 +import com.genersoft.iot.vmp.vmanager.bean.*;
27 import io.swagger.v3.oas.annotations.Operation; 23 import io.swagger.v3.oas.annotations.Operation;
28 import io.swagger.v3.oas.annotations.Parameter; 24 import io.swagger.v3.oas.annotations.Parameter;
29 import io.swagger.v3.oas.annotations.tags.Tag; 25 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -253,7 +249,7 @@ public class PlayController { @@ -253,7 +249,7 @@ public class PlayController {
253 @Parameter(name = "timeout", description = "推流超时时间(秒)", required = true) 249 @Parameter(name = "timeout", description = "推流超时时间(秒)", required = true)
254 @GetMapping("/broadcast/{deviceId}/{channelId}") 250 @GetMapping("/broadcast/{deviceId}/{channelId}")
255 @PostMapping("/broadcast/{deviceId}/{channelId}") 251 @PostMapping("/broadcast/{deviceId}/{channelId}")
256 - public AudioBroadcastResult broadcastApi(@PathVariable String deviceId, @PathVariable String channelId, Integer timeout) { 252 + public AudioBroadcastResult broadcastApi(@PathVariable String deviceId, @PathVariable String channelId, Integer timeout, Boolean broadcastMode) {
257 if (logger.isDebugEnabled()) { 253 if (logger.isDebugEnabled()) {
258 logger.debug("语音广播API调用"); 254 logger.debug("语音广播API调用");
259 } 255 }
@@ -265,15 +261,7 @@ public class PlayController { @@ -265,15 +261,7 @@ public class PlayController {
265 throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到通道: " + channelId); 261 throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到通道: " + channelId);
266 } 262 }
267 263
268 - return playService.audioBroadcast(device, channelId);  
269 -  
270 - }  
271 -  
272 - @GetMapping("/1111")  
273 - public void broadcastApi1() {  
274 - MediaServerItem defaultMediaServer = mediaServerService.getMediaServerForMinimumLoad(null);  
275 - Device device = storager.queryVideoDevice("34020000001320090001");  
276 - playService.talk(defaultMediaServer, device, "34020000001370000001", null, null, null); 264 + return playService.audioBroadcast(device, channelId, broadcastMode);
277 265
278 } 266 }
279 267
@@ -289,7 +277,7 @@ public class PlayController { @@ -289,7 +277,7 @@ public class PlayController {
289 } 277 }
290 // try { 278 // try {
291 // playService.stopAudioBroadcast(deviceId, channelId); 279 // playService.stopAudioBroadcast(deviceId, channelId);
292 -// } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) { 280 +// } catch (InvalidArgumentException | ParseException | SipException e) {
293 // logger.error("[命令发送失败] 停止语音: {}", e.getMessage()); 281 // logger.error("[命令发送失败] 停止语音: {}", e.getMessage());
294 // throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); 282 // throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
295 // } 283 // }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/AudioBroadcastEvent.java renamed to src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/AudioEvent.java
@@ -4,6 +4,6 @@ package com.genersoft.iot.vmp.vmanager.gb28181.play.bean; @@ -4,6 +4,6 @@ package com.genersoft.iot.vmp.vmanager.gb28181.play.bean;
4 /** 4 /**
5 * @author lin 5 * @author lin
6 */ 6 */
7 -public interface AudioBroadcastEvent { 7 +public interface AudioEvent {
8 void call(String msg); 8 void call(String msg);
9 } 9 }
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
@@ -185,7 +185,7 @@ public class ApiStreamController { @@ -185,7 +185,7 @@ public class ApiStreamController {
185 } 185 }
186 try { 186 try {
187 cmder.streamByeCmd(device, code, streamInfo.getStream(), null); 187 cmder.streamByeCmd(device, code, streamInfo.getStream(), null);
188 - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { 188 + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
189 JSONObject result = new JSONObject(); 189 JSONObject result = new JSONObject();
190 result.put("error","发送BYE失败:" + e.getMessage()); 190 result.put("error","发送BYE失败:" + e.getMessage());
191 return result; 191 return result;
web_src/config/index.js
@@ -12,7 +12,7 @@ module.exports = { @@ -12,7 +12,7 @@ module.exports = {
12 assetsPublicPath: './', 12 assetsPublicPath: './',
13 proxyTable: { 13 proxyTable: {
14 '/debug': { 14 '/debug': {
15 - target: 'https://default.wvp-pro.cn:18080', 15 + target: 'https://default.wvp-pro.cn:18082',
16 changeOrigin: true, 16 changeOrigin: true,
17 pathRewrite: { 17 pathRewrite: {
18 '^/debug': '/' 18 '^/debug': '/'
web_src/src/components/dialog/devicePlayer.vue
@@ -299,6 +299,10 @@ @@ -299,6 +299,10 @@
299 299
300 </el-tab-pane> 300 </el-tab-pane>
301 <el-tab-pane label="语音对讲" name="broadcast"> 301 <el-tab-pane label="语音对讲" name="broadcast">
  302 + <div style="padding: 0 10px">
  303 + <el-switch v-model="broadcastMode" :disabled="broadcastStatus !== -1" active-color="#409EFF" active-text="喊话"
  304 + inactive-text="对讲"></el-switch>
  305 + </div>
302 <div class="trank" style="text-align: center;"> 306 <div class="trank" style="text-align: center;">
303 <el-button @click="broadcastStatusClick()" :type="getBroadcastStatus()" :disabled="broadcastStatus === -2" 307 <el-button @click="broadcastStatusClick()" :type="getBroadcastStatus()" :disabled="broadcastStatus === -2"
304 circle icon="el-icon-microphone" style="font-size: 32px; padding: 24px;margin-top: 24px;"/> 308 circle icon="el-icon-microphone" style="font-size: 32px; padding: 24px;margin-top: 24px;"/>
@@ -390,6 +394,7 @@ export default { @@ -390,6 +394,7 @@ export default {
390 recordStartTime: 0, 394 recordStartTime: 0,
391 showTimeText: "00:00:00", 395 showTimeText: "00:00:00",
392 streamInfo: null, 396 streamInfo: null,
  397 + broadcastMode: true,
393 broadcastRtc: null, 398 broadcastRtc: null,
394 broadcastStatus: -1, // -2 正在释放资源 -1 默认状态 0 等待接通 1 接通成功 399 broadcastStatus: -1, // -2 正在释放资源 -1 默认状态 0 等待接通 1 接通成功
395 }; 400 };
@@ -648,7 +653,7 @@ export default { @@ -648,7 +653,7 @@ export default {
648 // 发起语音对讲 653 // 发起语音对讲
649 this.$axios({ 654 this.$axios({
650 method: 'get', 655 method: 'get',
651 - url: '/api/play/broadcast/' + this.deviceId + '/' + this.channelId + "?timeout=30" 656 + url: '/api/play/broadcast/' + this.deviceId + '/' + this.channelId + "?timeout=30&broadcastMode=" + this.broadcastMode
652 }).then( (res)=> { 657 }).then( (res)=> {
653 if (res.data.code == 0) { 658 if (res.data.code == 0) {
654 let streamInfo = res.data.data.streamInfo; 659 let streamInfo = res.data.data.streamInfo;