Commit 039fbf7e243d4bf0f46b44e7dae2a5d36e978056
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 | 63 | */ |
| 64 | 64 | private SipTransactionInfo sipTransactionInfo; |
| 65 | 65 | |
| 66 | + private MediaServerItem mediaServerItem; | |
| 67 | + | |
| 66 | 68 | |
| 67 | 69 | public String getDeviceId() { |
| 68 | 70 | return deviceId; |
| ... | ... | @@ -123,4 +125,12 @@ public class AudioBroadcastCatch { |
| 123 | 125 | public void setSipTransactionInfoByRequset(SIPResponse response) { |
| 124 | 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 | 49 | /** |
| 50 | 50 | * 设备推流的streamId |
| 51 | 51 | */ |
| 52 | - private String streamId; | |
| 52 | + private String stream; | |
| 53 | 53 | |
| 54 | 54 | /** |
| 55 | 55 | * 是否为tcp |
| ... | ... | @@ -117,6 +117,11 @@ public class SendRtpItem { |
| 117 | 117 | */ |
| 118 | 118 | private InviteStreamType playType; |
| 119 | 119 | |
| 120 | + /** | |
| 121 | + * 发流的同时收流 | |
| 122 | + */ | |
| 123 | + private String receiveStream; | |
| 124 | + | |
| 120 | 125 | public String getIp() { |
| 121 | 126 | return ip; |
| 122 | 127 | } |
| ... | ... | @@ -181,12 +186,12 @@ public class SendRtpItem { |
| 181 | 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 | 197 | public boolean isTcp() { |
| ... | ... | @@ -292,4 +297,12 @@ public class SendRtpItem { |
| 292 | 297 | public void setRtcp(boolean rtcp) { |
| 293 | 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
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
| ... | ... | @@ -94,12 +94,12 @@ public class SipRunner implements CommandLineRunner { |
| 94 | 94 | if (sendRtpItems.size() > 0) { |
| 95 | 95 | for (SendRtpItem sendRtpItem : sendRtpItems) { |
| 96 | 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 | 98 | if (mediaServerItem != null) { |
| 99 | 99 | Map<String, Object> param = new HashMap<>(); |
| 100 | 100 | param.put("vhost","__defaultVhost__"); |
| 101 | 101 | param.put("app",sendRtpItem.getApp()); |
| 102 | - param.put("stream",sendRtpItem.getStreamId()); | |
| 102 | + param.put("stream",sendRtpItem.getStream()); | |
| 103 | 103 | param.put("ssrc",sendRtpItem.getSsrc()); |
| 104 | 104 | JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param); |
| 105 | 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 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | 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 | 6 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 10 | 7 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| 11 | 8 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| ... | ... | @@ -131,7 +128,7 @@ public interface ISIPCommander { |
| 131 | 128 | */ |
| 132 | 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 | 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 | 32 | import org.springframework.context.annotation.DependsOn; |
| 33 | 33 | import org.springframework.stereotype.Component; |
| 34 | 34 | import org.springframework.util.ObjectUtils; |
| 35 | -import org.springframework.util.StringUtils; | |
| 36 | 35 | |
| 37 | 36 | import javax.sip.InvalidArgumentException; |
| 38 | 37 | import javax.sip.ResponseEvent; |
| ... | ... | @@ -584,9 +583,9 @@ public class SIPCommander implements ISIPCommander { |
| 584 | 583 | } |
| 585 | 584 | |
| 586 | 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 | 590 | if (device == null) { |
| 592 | 591 | return; |
| ... | ... | @@ -597,7 +596,7 @@ public class SIPCommander implements ISIPCommander { |
| 597 | 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 | 600 | HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); |
| 602 | 601 | subscribe.addSubscribe(hookSubscribeForStreamChange, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { |
| 603 | 602 | if (event != null) { |
| ... | ... | @@ -622,24 +621,27 @@ public class SIPCommander implements ISIPCommander { |
| 622 | 621 | content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); |
| 623 | 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 | 627 | content.append("a=sendrecv\r\n"); |
| 627 | 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 | 631 | // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 |
| 631 | 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 | 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 | 639 | errorEvent.response(e); |
| 638 | 640 | }), e -> { |
| 639 | 641 | // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 |
| 640 | 642 | ResponseEvent responseEvent = (ResponseEvent) e.event; |
| 641 | 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 | 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 | 694 | MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); |
| 695 | 695 | if (mediaServerItem != null) { |
| 696 | 696 | mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc()); |
| 697 | - zlmrtpServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStreamId()); | |
| 697 | + zlmrtpServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStream()); | |
| 698 | 698 | } |
| 699 | 699 | SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(platform, sendRtpItem); |
| 700 | 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 | 102 | } |
| 103 | 103 | String isUdp = sendRtpItem.isTcp() ? "0" : "1"; |
| 104 | 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 | 106 | sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp()); |
| 107 | 107 | Map<String, Object> param = new HashMap<>(12); |
| 108 | 108 | param.put("vhost","__defaultVhost__"); |
| 109 | 109 | param.put("app",sendRtpItem.getApp()); |
| 110 | - param.put("stream",sendRtpItem.getStreamId()); | |
| 110 | + param.put("stream",sendRtpItem.getStream()); | |
| 111 | 111 | param.put("ssrc", sendRtpItem.getSsrc()); |
| 112 | 112 | param.put("src_port", sendRtpItem.getLocalPort()); |
| 113 | 113 | param.put("pt", sendRtpItem.getPt()); |
| ... | ... | @@ -121,7 +121,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In |
| 121 | 121 | |
| 122 | 122 | if (mediaInfo == null) { |
| 123 | 123 | RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance( |
| 124 | - sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(), | |
| 124 | + sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStream(), | |
| 125 | 125 | sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(), |
| 126 | 126 | sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio()); |
| 127 | 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 | 97 | |
| 98 | 98 | if (sendRtpItem != null){ |
| 99 | 99 | logger.info("[收到bye] {}/{}", sendRtpItem.getPlatformId(), sendRtpItem.getChannelId()); |
| 100 | - String streamId = sendRtpItem.getStreamId(); | |
| 100 | + String streamId = sendRtpItem.getStream(); | |
| 101 | 101 | MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| 102 | 102 | if (mediaServerItem == null) { |
| 103 | 103 | return; |
| ... | ... | @@ -105,7 +105,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In |
| 105 | 105 | |
| 106 | 106 | Boolean ready = zlmrtpServerFactory.isStreamReady(mediaServerItem, sendRtpItem.getApp(), streamId); |
| 107 | 107 | if (!ready) { |
| 108 | - logger.info("[收到bye] 发现流{}/{}已经结束,不需处理", sendRtpItem.getApp(), sendRtpItem.getStreamId()); | |
| 108 | + logger.info("[收到bye] 发现流{}/{}已经结束,不需处理", sendRtpItem.getApp(), sendRtpItem.getStream()); | |
| 109 | 109 | return; |
| 110 | 110 | } |
| 111 | 111 | Map<String, Object> param = new HashMap<>(); |
| ... | ... | @@ -113,7 +113,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In |
| 113 | 113 | param.put("app",sendRtpItem.getApp()); |
| 114 | 114 | param.put("stream",streamId); |
| 115 | 115 | param.put("ssrc",sendRtpItem.getSsrc()); |
| 116 | - logger.info("[收到bye] 停止向上级推流:{}", streamId); | |
| 116 | + logger.info("[收到bye] 停止推流:{}", streamId); | |
| 117 | 117 | MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); |
| 118 | 118 | redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), callIdHeader.getCallId(), null); |
| 119 | 119 | zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param); |
| ... | ... | @@ -129,15 +129,14 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In |
| 129 | 129 | try { |
| 130 | 130 | logger.warn("[停止点播] {}/{}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| 131 | 131 | cmder.streamByeCmd(device, sendRtpItem.getChannelId(), streamId, null); |
| 132 | - } catch (InvalidArgumentException | ParseException | SipException | | |
| 133 | - SsrcTransactionNotFoundException e) { | |
| 132 | + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { | |
| 134 | 133 | logger.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); |
| 135 | 134 | } |
| 136 | 135 | } |
| 137 | 136 | |
| 138 | 137 | if (sendRtpItem.getPlayType().equals(InviteStreamType.PUSH)) { |
| 139 | 138 | MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, |
| 140 | - sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(), | |
| 139 | + sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(), | |
| 141 | 140 | sendRtpItem.getPlatformId(), null, null, sendRtpItem.getMediaServerId()); |
| 142 | 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 | 478 | if ("Playback".equalsIgnoreCase(sessionName)) { |
| 479 | 479 | sendRtpItem.setPlayType(InviteStreamType.PLAYBACK); |
| 480 | 480 | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, device.isSsrcCheck(), true); |
| 481 | - sendRtpItem.setStreamId(ssrcInfo.getStream()); | |
| 481 | + sendRtpItem.setStream(ssrcInfo.getStream()); | |
| 482 | 482 | // 写入redis, 超时时回复 |
| 483 | 483 | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| 484 | 484 | playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), |
| ... | ... | @@ -523,7 +523,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 523 | 523 | } |
| 524 | 524 | SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false); |
| 525 | 525 | logger.info(JSONObject.toJSONString(ssrcInfo)); |
| 526 | - sendRtpItem.setStreamId(ssrcInfo.getStream()); | |
| 526 | + sendRtpItem.setStream(ssrcInfo.getStream()); | |
| 527 | 527 | sendRtpItem.setSsrc(ssrc.equals(ssrcDefault) ? ssrcInfo.getSsrc() : ssrc); |
| 528 | 528 | |
| 529 | 529 | // 写入redis, 超时时回复 |
| ... | ... | @@ -533,12 +533,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 533 | 533 | redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), finalChannelId, callIdHeader.getCallId(), null); |
| 534 | 534 | }); |
| 535 | 535 | } else { |
| 536 | - sendRtpItem.setStreamId(playTransaction.getStream()); | |
| 536 | + sendRtpItem.setStream(playTransaction.getStream()); | |
| 537 | 537 | // 写入redis, 超时时回复 |
| 538 | 538 | redisCatchStorage.updateSendRTPSever(sendRtpItem); |
| 539 | 539 | JSONObject jsonObject = new JSONObject(); |
| 540 | 540 | jsonObject.put("app", sendRtpItem.getApp()); |
| 541 | - jsonObject.put("stream", sendRtpItem.getStreamId()); | |
| 541 | + jsonObject.put("stream", sendRtpItem.getStream()); | |
| 542 | 542 | hookEvent.response(mediaServerItem, jsonObject); |
| 543 | 543 | } |
| 544 | 544 | } |
| ... | ... | @@ -982,6 +982,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 982 | 982 | } |
| 983 | 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 | 1000 | String addressStr = sdp.getConnection().getAddress(); |
| 986 | 1001 | logger.info("设备{}请求语音流, 收流地址:{}:{},ssrc:{}, {}, 对讲方式:{}", requesterId, addressStr, port, ssrc, |
| 987 | 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 | 102 | String contentSubType = header.getContentSubType(); |
| 103 | 103 | if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) { |
| 104 | 104 | SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId()); |
| 105 | - String streamId = sendRtpItem.getStreamId(); | |
| 105 | + String streamId = sendRtpItem.getStream(); | |
| 106 | 106 | StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null); |
| 107 | 107 | if (null == streamInfo) { |
| 108 | 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 | 90 | |
| 91 | 91 | try { |
| 92 | 92 | cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); |
| 93 | - } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) { | |
| 93 | + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { | |
| 94 | 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 | 123 | } |
| 124 | 124 | |
| 125 | 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 | 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 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 10 | 10 | import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; |
| 11 | 11 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 12 | -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; | |
| 13 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 14 | 13 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 14 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; | |
| 15 | 15 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 16 | 16 | import com.genersoft.iot.vmp.media.zlm.dto.HookType; |
| 17 | 17 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| ... | ... | @@ -249,6 +249,7 @@ public class ZLMHttpHookListener { |
| 249 | 249 | String channelId = ssrcTransactionForAll.get(0).getChannelId(); |
| 250 | 250 | DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); |
| 251 | 251 | if (deviceChannel != null) { |
| 252 | + | |
| 252 | 253 | result.setEnable_audio(deviceChannel.isHasAudio()); |
| 253 | 254 | } |
| 254 | 255 | // 如果是录像下载就设置视频间隔十秒 |
| ... | ... | @@ -257,6 +258,11 @@ public class ZLMHttpHookListener { |
| 257 | 258 | result.setEnable_audio(true); |
| 258 | 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 | 267 | return result; |
| 262 | 268 | } |
| ... | ... | @@ -359,62 +365,30 @@ public class ZLMHttpHookListener { |
| 359 | 365 | } |
| 360 | 366 | }else if ("talk".equals(param.getApp())){ |
| 361 | 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 | 393 | }else{ |
| 420 | 394 | if (!"rtp".equals(param.getApp())){ |
| ... | ... | @@ -474,16 +448,21 @@ public class ZLMHttpHookListener { |
| 474 | 448 | ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); |
| 475 | 449 | Device device = deviceService.getDevice(platformId); |
| 476 | 450 | |
| 477 | - try { | |
| 451 | + | |
| 478 | 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 | 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 | 505 | logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); |
| 527 | 506 | } |
| 528 | 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 | 534 | try { |
| 556 | 535 | cmder.streamByeCmd(device, streamInfoForPlayBackCatch.getChannelId(), |
| 557 | 536 | streamInfoForPlayBackCatch.getStream(), null); |
| 558 | - } catch (InvalidArgumentException | ParseException | SipException | | |
| 559 | - SsrcTransactionNotFoundException e) { | |
| 537 | + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { | |
| 560 | 538 | logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage()); |
| 561 | 539 | } |
| 562 | 540 | } |
| ... | ... | @@ -572,6 +550,13 @@ public class ZLMHttpHookListener { |
| 572 | 550 | ret.put("close", false); |
| 573 | 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 | 560 | } else { |
| 576 | 561 | // 非国标流 推流/拉流代理 |
| 577 | 562 | // 拉流代理 |
| ... | ... | @@ -733,7 +718,7 @@ public class ZLMHttpHookListener { |
| 733 | 718 | logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage()); |
| 734 | 719 | } |
| 735 | 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 | 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 | 298 | public JSONObject stopSendRtp(MediaServerItem mediaServerItem, Map<String, Object> param) { |
| 295 | 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 | 229 | sendRtpItem.setPort(port); |
| 230 | 230 | sendRtpItem.setSsrc(ssrc); |
| 231 | 231 | sendRtpItem.setApp(app); |
| 232 | - sendRtpItem.setStreamId(stream); | |
| 232 | + sendRtpItem.setStream(stream); | |
| 233 | 233 | sendRtpItem.setPlatformId(platformId); |
| 234 | 234 | sendRtpItem.setChannelId(channelId); |
| 235 | 235 | sendRtpItem.setTcp(tcp); |
| ... | ... | @@ -290,6 +290,10 @@ public class ZLMRTPServerFactory { |
| 290 | 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 | 347 | result= true; |
| 344 | 348 | logger.info("[停止RTP推流] 成功"); |
| 345 | 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 | 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 | 12 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 13 | 13 | import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; |
| 14 | 14 | import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; |
| 15 | +import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioEvent; | |
| 15 | 16 | import gov.nist.javax.sip.message.SIPResponse; |
| 16 | 17 | |
| 17 | 18 | import javax.sip.InvalidArgumentException; |
| ... | ... | @@ -27,10 +28,6 @@ public interface IPlayService { |
| 27 | 28 | |
| 28 | 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 | 31 | void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, |
| 35 | 32 | ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, |
| 36 | 33 | InviteTimeOutCallback timeoutCallback); |
| ... | ... | @@ -57,7 +54,7 @@ public interface IPlayService { |
| 57 | 54 | |
| 58 | 55 | void zlmServerOnline(String mediaServerId); |
| 59 | 56 | |
| 60 | - AudioBroadcastResult audioBroadcast(Device device, String channelId); | |
| 57 | + AudioBroadcastResult audioBroadcast(Device device, String channelId, Boolean broadcastMode); | |
| 61 | 58 | void stopAudioBroadcast(String deviceId, String channelId); |
| 62 | 59 | |
| 63 | 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 | 67 | |
| 71 | 68 | void startSendRtpStreamHand(SendRtpItem sendRtpItem, ParentPlatform parentPlatform, |
| 72 | 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 | 202 | Map<String, Object> param = new HashMap<>(); |
| 203 | 203 | param.put("vhost", "__defaultVhost__"); |
| 204 | 204 | param.put("app", sendRtpItem.getApp()); |
| 205 | - param.put("stream", sendRtpItem.getStreamId()); | |
| 205 | + param.put("stream", sendRtpItem.getStream()); | |
| 206 | 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 | 253 | Map<String, Object> param = new HashMap<>(3); |
| 254 | 254 | param.put("vhost", "__defaultVhost__"); |
| 255 | 255 | param.put("app", sendRtpItem.getApp()); |
| 256 | - param.put("stream", sendRtpItem.getStreamId()); | |
| 256 | + param.put("stream", sendRtpItem.getStream()); | |
| 257 | 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 | 41 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 42 | 42 | import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| 43 | 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 | 45 | import gov.nist.javax.sip.message.SIPResponse; |
| 46 | 46 | import org.slf4j.Logger; |
| 47 | 47 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -134,8 +134,8 @@ public class PlayServiceImpl implements IPlayService { |
| 134 | 134 | |
| 135 | 135 | @Override |
| 136 | 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 | 139 | if (mediaServerItem == null) { |
| 140 | 140 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm"); |
| 141 | 141 | } |
| ... | ... | @@ -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 | 285 | String timeOutTaskKey = UUID.randomUUID().toString(); |
| 258 | - SSRCInfo finalSsrcInfo = ssrcInfo; | |
| 259 | - System.out.println("设置超时任务: " + timeOutTaskKey); | |
| 260 | 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 | 289 | timeoutCallback.run(); |
| 264 | 290 | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| 265 | 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 | 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 | 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 | 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 | 362 | dynamicTask.stop(timeOutTaskKey); |
| 421 | - mediaServerService.closeRTPServer(mediaServerItem, finalSsrcInfo.getStream()); | |
| 363 | + mediaServerService.closeRTPServer(mediaServerItem, sendRtpItem.getStream()); | |
| 422 | 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 | 388 | @Override |
| 435 | 389 | public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, |
| 436 | 390 | ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent, |
| ... | ... | @@ -446,7 +400,8 @@ public class PlayServiceImpl implements IPlayService { |
| 446 | 400 | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| 447 | 401 | try { |
| 448 | 402 | cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); |
| 449 | - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { | |
| 403 | + } catch (InvalidArgumentException | ParseException | SipException | | |
| 404 | + SsrcTransactionNotFoundException e) { | |
| 450 | 405 | logger.error("[点播超时], 发送BYE失败 {}", e.getMessage()); |
| 451 | 406 | } finally { |
| 452 | 407 | timeoutCallback.run(1, "收流超时"); |
| ... | ... | @@ -483,7 +438,7 @@ public class PlayServiceImpl implements IPlayService { |
| 483 | 438 | onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId); |
| 484 | 439 | hookEvent.response(mediaServerItemInuse, response); |
| 485 | 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 | 442 | String path = "snap"; |
| 488 | 443 | String fileName = device.getDeviceId() + "_" + channelId + ".jpg"; |
| 489 | 444 | // 请求截图 |
| ... | ... | @@ -652,8 +607,8 @@ public class PlayServiceImpl implements IPlayService { |
| 652 | 607 | |
| 653 | 608 | @Override |
| 654 | 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 | 612 | Device device = storager.queryVideoDevice(deviceId); |
| 658 | 613 | if (device == null) { |
| 659 | 614 | return; |
| ... | ... | @@ -666,9 +621,9 @@ public class PlayServiceImpl implements IPlayService { |
| 666 | 621 | |
| 667 | 622 | @Override |
| 668 | 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 | 627 | if (mediaServerItem == null || ssrcInfo == null) { |
| 673 | 628 | return; |
| 674 | 629 | } |
| ... | ... | @@ -792,7 +747,6 @@ public class PlayServiceImpl implements IPlayService { |
| 792 | 747 | } |
| 793 | 748 | |
| 794 | 749 | |
| 795 | - | |
| 796 | 750 | @Override |
| 797 | 751 | public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback) { |
| 798 | 752 | Device device = storager.queryVideoDevice(deviceId); |
| ... | ... | @@ -977,7 +931,7 @@ public class PlayServiceImpl implements IPlayService { |
| 977 | 931 | cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), |
| 978 | 932 | ssrcTransaction.getStream(), null); |
| 979 | 933 | } catch (InvalidArgumentException | ParseException | SipException | |
| 980 | - SsrcTransactionNotFoundException e) { | |
| 934 | + SsrcTransactionNotFoundException e) { | |
| 981 | 935 | logger.error("[zlm离线]为正在使用此zlm的设备, 发送BYE失败 {}", e.getMessage()); |
| 982 | 936 | } |
| 983 | 937 | } |
| ... | ... | @@ -986,7 +940,8 @@ public class PlayServiceImpl implements IPlayService { |
| 986 | 940 | } |
| 987 | 941 | |
| 988 | 942 | @Override |
| 989 | - public AudioBroadcastResult audioBroadcast(Device device, String channelId) { | |
| 943 | + public AudioBroadcastResult audioBroadcast(Device device, String channelId, Boolean broadcastMode) { | |
| 944 | + // TODO 必须多端口模式才支持语音喊话鹤语音对讲 | |
| 990 | 945 | if (device == null || channelId == null) { |
| 991 | 946 | return null; |
| 992 | 947 | } |
| ... | ... | @@ -997,15 +952,15 @@ public class PlayServiceImpl implements IPlayService { |
| 997 | 952 | return null; |
| 998 | 953 | } |
| 999 | 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 | 959 | String stream = device.getDeviceId() + "_" + channelId; |
| 1004 | - StreamInfo broadcast = mediaService.getStreamInfoByAppAndStream(mediaServerItem, "broadcast", stream, null, null, null, false); | |
| 1005 | 960 | AudioBroadcastResult audioBroadcastResult = new AudioBroadcastResult(); |
| 1006 | 961 | audioBroadcastResult.setApp(app); |
| 1007 | 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 | 964 | audioBroadcastResult.setCodec("G.711"); |
| 1010 | 965 | return audioBroadcastResult; |
| 1011 | 966 | } |
| ... | ... | @@ -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 | 1009 | cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> { |
| ... | ... | @@ -1053,19 +1020,18 @@ public class PlayServiceImpl implements IPlayService { |
| 1053 | 1020 | } |
| 1054 | 1021 | |
| 1055 | 1022 | |
| 1056 | - | |
| 1057 | 1023 | @Override |
| 1058 | 1024 | public void stopAudioBroadcast(String deviceId, String channelId) { |
| 1059 | 1025 | List<AudioBroadcastCatch> audioBroadcastCatchList = new ArrayList<>(); |
| 1060 | 1026 | if (channelId == null) { |
| 1061 | 1027 | audioBroadcastCatchList.addAll(audioBroadcastManager.get(deviceId)); |
| 1062 | - }else { | |
| 1028 | + } else { | |
| 1063 | 1029 | audioBroadcastCatchList.add(audioBroadcastManager.get(deviceId, channelId)); |
| 1064 | 1030 | } |
| 1065 | 1031 | if (audioBroadcastCatchList.size() > 0) { |
| 1066 | 1032 | for (AudioBroadcastCatch audioBroadcastCatch : audioBroadcastCatchList) { |
| 1067 | 1033 | Device device = deviceService.getDevice(deviceId); |
| 1068 | - if (device == null || audioBroadcastCatch == null ) { | |
| 1034 | + if (device == null || audioBroadcastCatch == null) { | |
| 1069 | 1035 | return; |
| 1070 | 1036 | } |
| 1071 | 1037 | SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(deviceId, audioBroadcastCatch.getChannelId(), null, null); |
| ... | ... | @@ -1075,7 +1041,7 @@ public class PlayServiceImpl implements IPlayService { |
| 1075 | 1041 | Map<String, Object> param = new HashMap<>(); |
| 1076 | 1042 | param.put("vhost", "__defaultVhost__"); |
| 1077 | 1043 | param.put("app", sendRtpItem.getApp()); |
| 1078 | - param.put("stream", sendRtpItem.getStreamId()); | |
| 1044 | + param.put("stream", sendRtpItem.getStream()); | |
| 1079 | 1045 | zlmresTfulUtils.stopSendRtp(mediaInfo, param); |
| 1080 | 1046 | try { |
| 1081 | 1047 | cmder.streamByeCmd(device, sendRtpItem.getChannelId(), audioBroadcastCatch.getSipTransactionInfo(), null); |
| ... | ... | @@ -1199,12 +1165,12 @@ public class PlayServiceImpl implements IPlayService { |
| 1199 | 1165 | |
| 1200 | 1166 | String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; |
| 1201 | 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 | 1169 | sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isRtcp()); |
| 1204 | 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 | 1174 | param.put("ssrc", sendRtpItem.getSsrc()); |
| 1209 | 1175 | param.put("src_port", sendRtpItem.getLocalPort()); |
| 1210 | 1176 | param.put("pt", sendRtpItem.getPt()); |
| ... | ... | @@ -1213,12 +1179,12 @@ public class PlayServiceImpl implements IPlayService { |
| 1213 | 1179 | param.put("is_udp", is_Udp); |
| 1214 | 1180 | if (!sendRtpItem.isTcp()) { |
| 1215 | 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 | 1185 | if (mediaInfo == null) { |
| 1220 | 1186 | RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance( |
| 1221 | - sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(), | |
| 1187 | + sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStream(), | |
| 1222 | 1188 | sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(), |
| 1223 | 1189 | sendRtpItem.getLocalPort(), sendRtpItem.getPt(), sendRtpItem.isUsePs(), sendRtpItem.isOnlyAudio()); |
| 1224 | 1190 | redisGbPlayMsgListener.sendMsgForStartSendRtpStream(sendRtpItem.getServerId(), requestPushStreamMsg, json -> { |
| ... | ... | @@ -1233,16 +1199,16 @@ public class PlayServiceImpl implements IPlayService { |
| 1233 | 1199 | if (zlmrtpServerFactory.releasePort(mediaInfo, sendRtpItem.getSsrc())) { |
| 1234 | 1200 | if (sendRtpItem.isTcpActive()) { |
| 1235 | 1201 | startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param); |
| 1236 | - }else { | |
| 1202 | + } else { | |
| 1237 | 1203 | param.put("dst_url", sendRtpItem.getIp()); |
| 1238 | 1204 | param.put("dst_port", sendRtpItem.getPort()); |
| 1239 | 1205 | startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| 1240 | 1206 | } |
| 1241 | 1207 | } |
| 1242 | - }else { | |
| 1208 | + } else { | |
| 1243 | 1209 | if (sendRtpItem.isTcpActive()) { |
| 1244 | 1210 | startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param); |
| 1245 | - }else { | |
| 1211 | + } else { | |
| 1246 | 1212 | param.put("dst_url", sendRtpItem.getIp()); |
| 1247 | 1213 | param.put("dst_port", sendRtpItem.getPort()); |
| 1248 | 1214 | startSendRtpStreamResult = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param); |
| ... | ... | @@ -1260,10 +1226,10 @@ public class PlayServiceImpl implements IPlayService { |
| 1260 | 1226 | if (jsonObject == null) { |
| 1261 | 1227 | logger.error("RTP推流失败: 请检查ZLM服务"); |
| 1262 | 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 | 1231 | } else { |
| 1266 | - logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"), JSON.toJSONString(param)); | |
| 1232 | + logger.error("RTP推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSON.toJSONString(param)); | |
| 1267 | 1233 | if (sendRtpItem.isOnlyAudio()) { |
| 1268 | 1234 | Device device = deviceService.getDevice(sendRtpItem.getDeviceId()); |
| 1269 | 1235 | AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); |
| ... | ... | @@ -1275,7 +1241,7 @@ public class PlayServiceImpl implements IPlayService { |
| 1275 | 1241 | logger.error("[命令发送失败] 停止语音对讲: {}", e.getMessage()); |
| 1276 | 1242 | } |
| 1277 | 1243 | } |
| 1278 | - }else { | |
| 1244 | + } else { | |
| 1279 | 1245 | // 向上级平台 |
| 1280 | 1246 | try { |
| 1281 | 1247 | commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId()); |
| ... | ... | @@ -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 | 378 | + sendRtpItem.getMediaServerId() + "_" |
| 379 | 379 | + sendRtpItem.getPlatformId() + "_" |
| 380 | 380 | + sendRtpItem.getChannelId() + "_" |
| 381 | - + sendRtpItem.getStreamId() + "_" | |
| 381 | + + sendRtpItem.getStream() + "_" | |
| 382 | 382 | + sendRtpItem.getCallId(); |
| 383 | 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 | 19 | import com.genersoft.iot.vmp.service.IPlayService; |
| 20 | 20 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 21 | 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 | 23 | import io.swagger.v3.oas.annotations.Operation; |
| 28 | 24 | import io.swagger.v3.oas.annotations.Parameter; |
| 29 | 25 | import io.swagger.v3.oas.annotations.tags.Tag; |
| ... | ... | @@ -253,7 +249,7 @@ public class PlayController { |
| 253 | 249 | @Parameter(name = "timeout", description = "推流超时时间(秒)", required = true) |
| 254 | 250 | @GetMapping("/broadcast/{deviceId}/{channelId}") |
| 255 | 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 | 253 | if (logger.isDebugEnabled()) { |
| 258 | 254 | logger.debug("语音广播API调用"); |
| 259 | 255 | } |
| ... | ... | @@ -265,15 +261,7 @@ public class PlayController { |
| 265 | 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 | 277 | } |
| 290 | 278 | // try { |
| 291 | 279 | // playService.stopAudioBroadcast(deviceId, channelId); |
| 292 | -// } catch (InvalidArgumentException | ParseException | SsrcTransactionNotFoundException | SipException e) { | |
| 280 | +// } catch (InvalidArgumentException | ParseException | SipException e) { | |
| 293 | 281 | // logger.error("[命令发送失败] 停止语音: {}", e.getMessage()); |
| 294 | 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
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
| ... | ... | @@ -185,7 +185,7 @@ public class ApiStreamController { |
| 185 | 185 | } |
| 186 | 186 | try { |
| 187 | 187 | cmder.streamByeCmd(device, code, streamInfo.getStream(), null); |
| 188 | - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { | |
| 188 | + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { | |
| 189 | 189 | JSONObject result = new JSONObject(); |
| 190 | 190 | result.put("error","发送BYE失败:" + e.getMessage()); |
| 191 | 191 | return result; | ... | ... |
web_src/config/index.js
web_src/src/components/dialog/devicePlayer.vue
| ... | ... | @@ -299,6 +299,10 @@ |
| 299 | 299 | |
| 300 | 300 | </el-tab-pane> |
| 301 | 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 | 306 | <div class="trank" style="text-align: center;"> |
| 303 | 307 | <el-button @click="broadcastStatusClick()" :type="getBroadcastStatus()" :disabled="broadcastStatus === -2" |
| 304 | 308 | circle icon="el-icon-microphone" style="font-size: 32px; padding: 24px;margin-top: 24px;"/> |
| ... | ... | @@ -390,6 +394,7 @@ export default { |
| 390 | 394 | recordStartTime: 0, |
| 391 | 395 | showTimeText: "00:00:00", |
| 392 | 396 | streamInfo: null, |
| 397 | + broadcastMode: true, | |
| 393 | 398 | broadcastRtc: null, |
| 394 | 399 | broadcastStatus: -1, // -2 正在释放资源 -1 默认状态 0 等待接通 1 接通成功 |
| 395 | 400 | }; |
| ... | ... | @@ -648,7 +653,7 @@ export default { |
| 648 | 653 | // 发起语音对讲 |
| 649 | 654 | this.$axios({ |
| 650 | 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 | 657 | }).then( (res)=> { |
| 653 | 658 | if (res.data.code == 0) { |
| 654 | 659 | let streamInfo = res.data.data.streamInfo; | ... | ... |