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