Commit 100252a253263321873e79d43dff94e19defe353

Authored by 648540858
1 parent a209d173

完善语音对讲

src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java
... ... @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.conf.redis;
3 3  
4 4 import com.genersoft.iot.vmp.common.VideoManagerConstants;
5 5 import com.genersoft.iot.vmp.service.redisMsg.*;
  6 +import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
6 7 import org.springframework.beans.factory.annotation.Autowired;
7 8 import org.springframework.cache.annotation.CachingConfigurerSupport;
8 9 import org.springframework.context.annotation.Bean;
... ... @@ -13,8 +14,6 @@ import org.springframework.data.redis.listener.PatternTopic;
13 14 import org.springframework.data.redis.listener.RedisMessageListenerContainer;
14 15 import org.springframework.data.redis.serializer.StringRedisSerializer;
15 16  
16   -import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
17   -
18 17  
19 18 /**
20 19 * @description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/AudioBroadcastCatch.java
1 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2  
3 3  
  4 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
4 5 import gov.nist.javax.sip.message.SIPResponse;
5 6  
6 7 /**
... ... @@ -10,10 +11,18 @@ import gov.nist.javax.sip.message.SIPResponse;
10 11 public class AudioBroadcastCatch {
11 12  
12 13  
13   - public AudioBroadcastCatch(String deviceId, String channelId, AudioBroadcastCatchStatus status) {
  14 + public AudioBroadcastCatch(String deviceId,
  15 + String channelId,
  16 + AudioBroadcastCatchStatus status,
  17 + MediaServerItem mediaServerItem,
  18 + String app,
  19 + String stream) {
14 20 this.deviceId = deviceId;
15 21 this.channelId = channelId;
16 22 this.status = status;
  23 + this.mediaServerItem = mediaServerItem;
  24 + this.app = app;
  25 + this.stream = stream;
17 26 }
18 27  
19 28 public AudioBroadcastCatch() {
... ... @@ -30,6 +39,21 @@ public class AudioBroadcastCatch {
30 39 private String channelId;
31 40  
32 41 /**
  42 + * 使用的流媒体
  43 + */
  44 + private MediaServerItem mediaServerItem;
  45 +
  46 + /**
  47 + * 待推送给设备的流应用名
  48 + */
  49 + private String app;
  50 +
  51 + /**
  52 + * 待推送给设备的流ID
  53 + */
  54 + private String stream;
  55 +
  56 + /**
33 57 * 语音广播状态
34 58 */
35 59 private AudioBroadcastCatchStatus status;
... ... @@ -68,6 +92,30 @@ public class AudioBroadcastCatch {
68 92 return sipTransactionInfo;
69 93 }
70 94  
  95 + public MediaServerItem getMediaServerItem() {
  96 + return mediaServerItem;
  97 + }
  98 +
  99 + public void setMediaServerItem(MediaServerItem mediaServerItem) {
  100 + this.mediaServerItem = mediaServerItem;
  101 + }
  102 +
  103 + public String getApp() {
  104 + return app;
  105 + }
  106 +
  107 + public void setApp(String app) {
  108 + this.app = app;
  109 + }
  110 +
  111 + public String getStream() {
  112 + return stream;
  113 + }
  114 +
  115 + public void setStream(String stream) {
  116 + this.stream = stream;
  117 + }
  118 +
71 119 public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
72 120 this.sipTransactionInfo = sipTransactionInfo;
73 121 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
... ... @@ -903,8 +903,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
903 903  
904 904 // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
905 905 Device device = redisCatchStorage.getDevice(requesterId);
906   - AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(requesterId, channelId);
907   - if (audioBroadcastCatch == null) {
  906 + AudioBroadcastCatch broadcastCatch = audioBroadcastManager.get(requesterId, channelId);
  907 + if (broadcastCatch == null) {
908 908 logger.warn("来自设备的Invite请求非语音广播,已忽略,requesterId: {}/{}", requesterId, channelId);
909 909 try {
910 910 responseAck(request, Response.FORBIDDEN);
... ... @@ -915,13 +915,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
915 915 }
916 916 if (device != null) {
917 917 logger.info("收到设备" + requesterId + "的语音广播Invite请求");
918   - String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + device.getDeviceId() + audioBroadcastCatch.getChannelId();
  918 + String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + device.getDeviceId() + broadcastCatch.getChannelId();
919 919 dynamicTask.stop(key);
920 920 try {
921 921 responseAck(request, Response.TRYING);
922 922 } catch (SipException | InvalidArgumentException | ParseException e) {
923 923 logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage());
924   - playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  924 + playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId());
925 925 return;
926 926 }
927 927 String contentString = new String(request.getRawContent());
... ... @@ -977,7 +977,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
977 977 responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
978 978 } catch (SipException | InvalidArgumentException | ParseException e) {
979 979 logger.error("[命令发送失败] invite 不支持的媒体格式: {}", e.getMessage());
980   - playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  980 + playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId());
981 981 return;
982 982 }
983 983 return;
... ... @@ -986,19 +986,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
986 986 logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}, {}", requesterId, addressStr, port, ssrc,
987 987 mediaTransmissionTCP ? (tcpActive? "TCP主动":"TCP被动") : "UDP");
988 988  
989   - MediaServerItem mediaServerItem = playService.getNewMediaServerItem(device);
990   - if (mediaServerItem == null) {
991   - logger.warn("未找到可用的zlm");
992   - try {
993   - responseAck(request, Response.BUSY_HERE);
994   - } catch (SipException | InvalidArgumentException | ParseException e) {
995   - logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage());
996   - playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
997   - }
998   - return;
999   - }
  989 + MediaServerItem mediaServerItem = broadcastCatch.getMediaServerItem();
1000 990 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
1001   - device.getDeviceId(), audioBroadcastCatch.getChannelId(),
  991 + device.getDeviceId(), broadcastCatch.getChannelId(),
1002 992 mediaTransmissionTCP, false);
1003 993  
1004 994 if (sendRtpItem == null) {
... ... @@ -1007,22 +997,20 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1007 997 responseAck(request, Response.BUSY_HERE);
1008 998 } catch (SipException | InvalidArgumentException | ParseException e) {
1009 999 logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
1010   - playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  1000 + playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId());
1011 1001 return;
1012 1002 }
1013 1003 return;
1014 1004 }
1015 1005  
1016   - String app = "broadcast";
1017   - String stream = device.getDeviceId() + "_" + audioBroadcastCatch.getChannelId();
1018 1006  
1019 1007 CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
1020 1008 sendRtpItem.setPlayType(InviteStreamType.TALK);
1021 1009 sendRtpItem.setCallId(callIdHeader.getCallId());
1022 1010 sendRtpItem.setPlatformId(requesterId);
1023 1011 sendRtpItem.setStatus(1);
1024   - sendRtpItem.setApp(app);
1025   - sendRtpItem.setStreamId(stream);
  1012 + sendRtpItem.setApp(broadcastCatch.getApp());
  1013 + sendRtpItem.setStreamId(broadcastCatch.getStream());
1026 1014 sendRtpItem.setPt(8);
1027 1015 sendRtpItem.setUsePs(false);
1028 1016 sendRtpItem.setRtcp(false);
... ... @@ -1034,22 +1022,22 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
1034 1022  
1035 1023 redisCatchStorage.updateSendRTPSever(sendRtpItem);
1036 1024  
1037   - Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, app, stream);
  1025 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, broadcastCatch.getApp(), broadcastCatch.getStream());
1038 1026 if (streamReady) {
1039 1027 sendOk(device, sendRtpItem, sdp, request, mediaServerItem, mediaTransmissionTCP, ssrc);
1040 1028 }else {
1041   - logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", app, stream);
  1029 + logger.warn("[语音通话], 未发现待推送的流,app={},stream={}", broadcastCatch.getApp(), broadcastCatch.getStream());
1042 1030 try {
1043 1031 responseAck(request, Response.GONE);
1044 1032 } catch (SipException | InvalidArgumentException | ParseException e) {
1045 1033 logger.error("[命令发送失败] 语音通话 回复410失败, {}", e.getMessage());
1046 1034 return;
1047 1035 }
1048   - playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  1036 + playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId());
1049 1037 }
1050 1038 } catch (SdpException e) {
1051 1039 logger.error("[SDP解析异常]", e);
1052   - playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId());
  1040 + playService.stopAudioBroadcast(device.getDeviceId(), broadcastCatch.getChannelId());
1053 1041 }
1054 1042 } else {
1055 1043 logger.warn("来自无效设备/平台的请求");
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -274,18 +274,17 @@ public class ZLMHttpHookListener {
274 274 logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
275 275 }
276 276  
277   -
  277 + MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
278 278 JSONObject json = (JSONObject) JSON.toJSON(param);
279 279 taskExecutor.execute(() -> {
280 280 ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
281 281 if (subscribe != null) {
282   - MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
  282 +
283 283 if (mediaInfo != null) {
284 284 subscribe.response(mediaInfo, json);
285 285 }
286 286 }
287 287 // 流消失移除redis play
288   - List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
289 288 if (param.isRegist()) {
290 289 if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
291 290 || param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
... ... @@ -343,7 +342,7 @@ public class ZLMHttpHookListener {
343 342 }
344 343 // 开启语音对讲通道
345 344 try {
346   - playService.audioBroadcastCmd(device, channelId, 60, (msg)->{
  345 + playService.audioBroadcastCmd(device, channelId, 60, mediaInfo, param.getApp(), param.getStream(), (msg)->{
347 346 logger.info("[语音对讲] 通道建立成功, device: {}, channel: {}", deviceId, channelId);
348 347 });
349 348 } catch (InvalidArgumentException | ParseException | SipException e) {
... ... @@ -375,7 +374,7 @@ public class ZLMHttpHookListener {
375 374 if (sendRtpItem == null) {
376 375 // TODO 可能数据错误,重新开启语音通道
377 376 }else {
378   - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
  377 + MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
379 378 logger.info("rtp/{}开始向上级推流, 目标={}:{},SSRC={}", sendRtpItem.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc());
380 379 Map<String, Object> sendParam = new HashMap<>(12);
381 380 sendParam.put("vhost","__defaultVhost__");
... ... @@ -389,12 +388,12 @@ public class ZLMHttpHookListener {
389 388  
390 389 JSONObject jsonObject;
391 390 if (sendRtpItem.isTcpActive()) {
392   - jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, sendParam);
  391 + jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaServerItem, sendParam);
393 392 } else {
394 393 sendParam.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
395 394 sendParam.put("dst_url", sendRtpItem.getIp());
396 395 sendParam.put("dst_port", sendRtpItem.getPort());
397   - jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, sendParam);
  396 + jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaServerItem, sendParam);
398 397 }
399 398 if (jsonObject != null && jsonObject.getInteger("code") == 0) {
400 399 logger.info("[语音对讲] 自动推流成功, device: {}, channel: {}", deviceId, channelId);
... ...
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
... ... @@ -12,9 +12,7 @@ import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
12 12 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
13 13 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
14 14 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
15   -import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
16 15 import gov.nist.javax.sip.message.SIPResponse;
17   -import org.springframework.web.context.request.async.DeferredResult;
18 16  
19 17 import javax.sip.InvalidArgumentException;
20 18 import javax.sip.SipException;
... ... @@ -62,7 +60,7 @@ public interface IPlayService {
62 60 AudioBroadcastResult audioBroadcast(Device device, String channelId);
63 61 void stopAudioBroadcast(String deviceId, String channelId);
64 62  
65   - void audioBroadcastCmd(Device device, String channelId, int timeout, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
  63 + void audioBroadcastCmd(Device device, String channelId, int timeout, MediaServerItem mediaServerItem, String sourceApp, String sourceStream, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException;
66 64  
67 65 void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
68 66  
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
... ... @@ -1011,7 +1011,7 @@ public class PlayServiceImpl implements IPlayService {
1011 1011 }
1012 1012  
1013 1013 @Override
1014   - public void audioBroadcastCmd(Device device, String channelId, int timeout, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException {
  1014 + public void audioBroadcastCmd(Device device, String channelId, int timeout, MediaServerItem mediaServerItem, String sourceApp, String sourceStream, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException {
1015 1015 if (device == null || channelId == null) {
1016 1016 return;
1017 1017 }
... ... @@ -1027,7 +1027,6 @@ public class PlayServiceImpl implements IPlayService {
1027 1027 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(device.getDeviceId(), channelId, null, null);
1028 1028 if (sendRtpItem != null && sendRtpItem.isOnlyAudio()) {
1029 1029 // 查询流是否存在,不存在则认为是异常状态
1030   - MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
1031 1030 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, sendRtpItem.getApp(), sendRtpItem.getStreamId());
1032 1031 if (streamReady) {
1033 1032 logger.warn("语音广播已经开启: {}", channelId);
... ... @@ -1042,7 +1041,8 @@ public class PlayServiceImpl implements IPlayService {
1042 1041 // 发送通知
1043 1042 cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> {
1044 1043 // 发送成功
1045   - AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId, AudioBroadcastCatchStatus.Ready);
  1044 + AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId,
  1045 + AudioBroadcastCatchStatus.Ready, mediaServerItem, sourceApp, sourceStream);
1046 1046 audioBroadcastManager.update(audioBroadcastCatch);
1047 1047 }, eventResultForError -> {
1048 1048 // 发送失败
... ...