Commit 28f4f688dd37cbce7f7e2ff4a939d0701f2a8bbe
1 parent
fc90cd79
优化语音遇到错误时主动终止对讲流程
Showing
6 changed files
with
42 additions
and
35 deletions
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| @@ -69,6 +69,7 @@ public class VideoManagerConstants { | @@ -69,6 +69,7 @@ public class VideoManagerConstants { | ||
| 69 | public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; | 69 | public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; |
| 70 | 70 | ||
| 71 | public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_"; | 71 | public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_"; |
| 72 | + public static final String BROADCAST_WAITE_INVITE = "task_broadcast_waite_invite_"; | ||
| 72 | 73 | ||
| 73 | 74 | ||
| 74 | 75 |
src/main/java/com/genersoft/iot/vmp/gb28181/session/AudioBroadcastManager.java
| @@ -23,10 +23,6 @@ public class AudioBroadcastManager { | @@ -23,10 +23,6 @@ public class AudioBroadcastManager { | ||
| 23 | 23 | ||
| 24 | public static Map<String, AudioBroadcastCatch> data = new ConcurrentHashMap<>(); | 24 | public static Map<String, AudioBroadcastCatch> data = new ConcurrentHashMap<>(); |
| 25 | 25 | ||
| 26 | - public void add(AudioBroadcastCatch audioBroadcastCatch) { | ||
| 27 | - this.update(audioBroadcastCatch); | ||
| 28 | - } | ||
| 29 | - | ||
| 30 | public void update(AudioBroadcastCatch audioBroadcastCatch) { | 26 | public void update(AudioBroadcastCatch audioBroadcastCatch) { |
| 31 | if (SipUtils.isFrontEnd(audioBroadcastCatch.getDeviceId())) { | 27 | if (SipUtils.isFrontEnd(audioBroadcastCatch.getDeviceId())) { |
| 32 | data.put(audioBroadcastCatch.getDeviceId(), audioBroadcastCatch); | 28 | data.put(audioBroadcastCatch.getDeviceId(), audioBroadcastCatch); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
| @@ -49,8 +49,6 @@ public class DeferredResultHolder { | @@ -49,8 +49,6 @@ public class DeferredResultHolder { | ||
| 49 | 49 | ||
| 50 | public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; | 50 | public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; |
| 51 | 51 | ||
| 52 | - public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST"; | ||
| 53 | - | ||
| 54 | private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>(); | 52 | private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>(); |
| 55 | 53 | ||
| 56 | 54 |
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.fastjson2.JSONObject; | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | +import com.genersoft.iot.vmp.common.VideoManagerConstants; | ||
| 4 | import com.genersoft.iot.vmp.conf.DynamicTask; | 5 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 5 | import com.genersoft.iot.vmp.conf.SipConfig; | 6 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 6 | import com.genersoft.iot.vmp.conf.UserSetting; | 7 | import com.genersoft.iot.vmp.conf.UserSetting; |
| @@ -914,11 +915,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -914,11 +915,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 914 | } | 915 | } |
| 915 | if (device != null) { | 916 | if (device != null) { |
| 916 | logger.info("收到设备" + requesterId + "的语音广播Invite请求"); | 917 | logger.info("收到设备" + requesterId + "的语音广播Invite请求"); |
| 917 | - | 918 | + String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + request.getCallIdHeader().getCallId(); |
| 919 | + dynamicTask.stop(key); | ||
| 918 | try { | 920 | try { |
| 919 | responseAck(request, Response.TRYING); | 921 | responseAck(request, Response.TRYING); |
| 920 | } catch (SipException | InvalidArgumentException | ParseException e) { | 922 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 921 | logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage()); | 923 | logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage()); |
| 924 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | ||
| 925 | + return; | ||
| 922 | } | 926 | } |
| 923 | String contentString = new String(request.getRawContent()); | 927 | String contentString = new String(request.getRawContent()); |
| 924 | // jainSip不支持y=字段, 移除移除以解析。 | 928 | // jainSip不支持y=字段, 移除移除以解析。 |
| @@ -973,6 +977,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -973,6 +977,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 973 | responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 | 977 | responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 |
| 974 | } catch (SipException | InvalidArgumentException | ParseException e) { | 978 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 975 | logger.error("[命令发送失败] invite 不支持的媒体格式: {}", e.getMessage()); | 979 | logger.error("[命令发送失败] invite 不支持的媒体格式: {}", e.getMessage()); |
| 980 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | ||
| 981 | + return; | ||
| 976 | } | 982 | } |
| 977 | return; | 983 | return; |
| 978 | } | 984 | } |
| @@ -987,6 +993,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -987,6 +993,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 987 | responseAck(request, Response.BUSY_HERE); | 993 | responseAck(request, Response.BUSY_HERE); |
| 988 | } catch (SipException | InvalidArgumentException | ParseException e) { | 994 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 989 | logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage()); | 995 | logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage()); |
| 996 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | ||
| 990 | } | 997 | } |
| 991 | return; | 998 | return; |
| 992 | } | 999 | } |
| @@ -1000,6 +1007,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -1000,6 +1007,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 1000 | responseAck(request, Response.BUSY_HERE); | 1007 | responseAck(request, Response.BUSY_HERE); |
| 1001 | } catch (SipException | InvalidArgumentException | ParseException e) { | 1008 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 1002 | logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage()); | 1009 | logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage()); |
| 1010 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | ||
| 1011 | + return; | ||
| 1003 | } | 1012 | } |
| 1004 | return; | 1013 | return; |
| 1005 | } | 1014 | } |
| @@ -1034,11 +1043,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | @@ -1034,11 +1043,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements | ||
| 1034 | responseAck(request, Response.GONE); | 1043 | responseAck(request, Response.GONE); |
| 1035 | } catch (SipException | InvalidArgumentException | ParseException e) { | 1044 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 1036 | logger.error("[命令发送失败] 语音通话 回复410失败, {}", e.getMessage()); | 1045 | logger.error("[命令发送失败] 语音通话 回复410失败, {}", e.getMessage()); |
| 1046 | + return; | ||
| 1037 | } | 1047 | } |
| 1038 | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | 1048 | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); |
| 1039 | } | 1049 | } |
| 1040 | } catch (SdpException e) { | 1050 | } catch (SdpException e) { |
| 1041 | logger.error("[SDP解析异常]", e); | 1051 | logger.error("[SDP解析异常]", e); |
| 1052 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | ||
| 1042 | } | 1053 | } |
| 1043 | } else { | 1054 | } else { |
| 1044 | logger.warn("来自无效设备/平台的请求"); | 1055 | logger.warn("来自无效设备/平台的请求"); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
| 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; | 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; |
| 2 | 2 | ||
| 3 | -import com.alibaba.fastjson2.JSONObject; | 3 | +import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 4 | +import com.genersoft.iot.vmp.conf.DynamicTask; | ||
| 4 | import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch; | 5 | import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch; |
| 5 | import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatchStatus; | 6 | import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatchStatus; |
| 6 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 7 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 7 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | 8 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 8 | import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; | 9 | import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; |
| 9 | -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | ||
| 10 | -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | ||
| 11 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; | 10 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| 12 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; | 11 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| 13 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; | 12 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; |
| 14 | -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; | 13 | +import com.genersoft.iot.vmp.service.IPlayService; |
| 15 | import gov.nist.javax.sip.message.SIPRequest; | 14 | import gov.nist.javax.sip.message.SIPRequest; |
| 16 | import org.dom4j.Element; | 15 | import org.dom4j.Element; |
| 17 | import org.slf4j.Logger; | 16 | import org.slf4j.Logger; |
| @@ -38,11 +37,14 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i | @@ -38,11 +37,14 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i | ||
| 38 | private ResponseMessageHandler responseMessageHandler; | 37 | private ResponseMessageHandler responseMessageHandler; |
| 39 | 38 | ||
| 40 | @Autowired | 39 | @Autowired |
| 41 | - private DeferredResultHolder deferredResultHolder; | 40 | + private DynamicTask dynamicTask; |
| 42 | 41 | ||
| 43 | @Autowired | 42 | @Autowired |
| 44 | private AudioBroadcastManager audioBroadcastManager; | 43 | private AudioBroadcastManager audioBroadcastManager; |
| 45 | 44 | ||
| 45 | + @Autowired | ||
| 46 | + private IPlayService playService; | ||
| 47 | + | ||
| 46 | @Override | 48 | @Override |
| 47 | public void afterPropertiesSet() throws Exception { | 49 | public void afterPropertiesSet() throws Exception { |
| 48 | responseMessageHandler.addHandler(cmdType, this); | 50 | responseMessageHandler.addHandler(cmdType, this); |
| @@ -50,33 +52,33 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i | @@ -50,33 +52,33 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i | ||
| 50 | 52 | ||
| 51 | @Override | 53 | @Override |
| 52 | public void handForDevice(RequestEvent evt, Device device, Element rootElement) { | 54 | public void handForDevice(RequestEvent evt, Device device, Element rootElement) { |
| 53 | - try { | ||
| 54 | - String channelId = getText(rootElement, "DeviceID"); | ||
| 55 | - String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId() + channelId; | ||
| 56 | - | ||
| 57 | - // 此处是对本平台发出Broadcast指令的应答 | ||
| 58 | - JSONObject json = new JSONObject(); | ||
| 59 | - XmlUtil.node2Json(rootElement, json); | ||
| 60 | - if (logger.isDebugEnabled()) { | ||
| 61 | - logger.debug(json.toJSONString()); | ||
| 62 | - } | ||
| 63 | - RequestMessage msg = new RequestMessage(); | ||
| 64 | - msg.setKey(key); | ||
| 65 | - msg.setData(json); | ||
| 66 | - deferredResultHolder.invokeAllResult(msg); | ||
| 67 | - | ||
| 68 | 55 | ||
| 56 | + String channelId = getText(rootElement, "DeviceID"); | ||
| 57 | + SIPRequest request = (SIPRequest) evt.getRequest(); | ||
| 58 | + try { | ||
| 69 | if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) { | 59 | if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) { |
| 70 | // 回复410 | 60 | // 回复410 |
| 71 | responseAck((SIPRequest) evt.getRequest(), Response.GONE); | 61 | responseAck((SIPRequest) evt.getRequest(), Response.GONE); |
| 72 | return; | 62 | return; |
| 73 | } | 63 | } |
| 74 | - logger.info("收到语音广播的回复:{}/{}", device.getDeviceId(), channelId ); | ||
| 75 | - AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), channelId); | ||
| 76 | - audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.WaiteInvite); | ||
| 77 | - audioBroadcastManager.update(audioBroadcastCatch); | 64 | + String result = getText(rootElement, "Result"); |
| 65 | + logger.info("[语音广播]回复:{}, {}/{}", result, device.getDeviceId(), channelId ); | ||
| 66 | + | ||
| 78 | // 回复200 OK | 67 | // 回复200 OK |
| 79 | - responseAck((SIPRequest) evt.getRequest(), Response.OK); | 68 | + responseAck(request, Response.OK); |
| 69 | + if (result.equalsIgnoreCase("OK")) { | ||
| 70 | + AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(device.getDeviceId(), channelId); | ||
| 71 | + audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.WaiteInvite); | ||
| 72 | + audioBroadcastManager.update(audioBroadcastCatch); | ||
| 73 | + // 等待invite消息, 超时则结束 | ||
| 74 | + String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + request.getCallIdHeader().getCallId(); | ||
| 75 | + dynamicTask.startDelay(key, ()->{ | ||
| 76 | + logger.info("[语音广播]等待invite消息超时:{}/{}", device.getDeviceId(), channelId); | ||
| 77 | + playService.stopAudioBroadcast(device.getDeviceId(), channelId); | ||
| 78 | + }, 2000); | ||
| 79 | + }else { | ||
| 80 | + playService.stopAudioBroadcast(device.getDeviceId(), channelId); | ||
| 81 | + } | ||
| 80 | } catch (ParseException | SipException | InvalidArgumentException e) { | 82 | } catch (ParseException | SipException | InvalidArgumentException e) { |
| 81 | logger.error("[命令发送失败] 国标级联 语音喊话: {}", e.getMessage()); | 83 | logger.error("[命令发送失败] 国标级联 语音喊话: {}", e.getMessage()); |
| 82 | } | 84 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| @@ -1045,8 +1045,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -1045,8 +1045,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 1045 | event.call("语音广播已经开启"); | 1045 | event.call("语音广播已经开启"); |
| 1046 | return; | 1046 | return; |
| 1047 | } else { | 1047 | } else { |
| 1048 | - audioBroadcastManager.del(deviceChannel.getDeviceId(), channelId); | ||
| 1049 | - redisCatchStorage.deleteSendRTPServer(device.getDeviceId(), channelId, sendRtpItem.getCallId(), sendRtpItem.getStreamId()); | 1048 | + stopAudioBroadcast(device.getDeviceId(), channelId); |
| 1050 | } | 1049 | } |
| 1051 | } | 1050 | } |
| 1052 | } | 1051 | } |
| @@ -1055,7 +1054,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -1055,7 +1054,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 1055 | cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> { | 1054 | cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> { |
| 1056 | // 发送成功 | 1055 | // 发送成功 |
| 1057 | AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId, AudioBroadcastCatchStatus.Ready); | 1056 | AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId, AudioBroadcastCatchStatus.Ready); |
| 1058 | - audioBroadcastManager.add(audioBroadcastCatch); | 1057 | + audioBroadcastManager.update(audioBroadcastCatch); |
| 1059 | }, eventResultForError -> { | 1058 | }, eventResultForError -> { |
| 1060 | // 发送失败 | 1059 | // 发送失败 |
| 1061 | logger.error("语音广播发送失败: {}:{}", channelId, eventResultForError.msg); | 1060 | logger.error("语音广播发送失败: {}:{}", channelId, eventResultForError.msg); |