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 | 69 | public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; |
| 70 | 70 | |
| 71 | 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 | 23 | |
| 24 | 24 | public static Map<String, AudioBroadcastCatch> data = new ConcurrentHashMap<>(); |
| 25 | 25 | |
| 26 | - public void add(AudioBroadcastCatch audioBroadcastCatch) { | |
| 27 | - this.update(audioBroadcastCatch); | |
| 28 | - } | |
| 29 | - | |
| 30 | 26 | public void update(AudioBroadcastCatch audioBroadcastCatch) { |
| 31 | 27 | if (SipUtils.isFrontEnd(audioBroadcastCatch.getDeviceId())) { |
| 32 | 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 | 49 | |
| 50 | 50 | public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; |
| 51 | 51 | |
| 52 | - public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST"; | |
| 53 | - | |
| 54 | 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 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | +import com.genersoft.iot.vmp.common.VideoManagerConstants; | |
| 4 | 5 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 5 | 6 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 6 | 7 | import com.genersoft.iot.vmp.conf.UserSetting; |
| ... | ... | @@ -914,11 +915,14 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 914 | 915 | } |
| 915 | 916 | if (device != null) { |
| 916 | 917 | logger.info("收到设备" + requesterId + "的语音广播Invite请求"); |
| 917 | - | |
| 918 | + String key = VideoManagerConstants.BROADCAST_WAITE_INVITE + request.getCallIdHeader().getCallId(); | |
| 919 | + dynamicTask.stop(key); | |
| 918 | 920 | try { |
| 919 | 921 | responseAck(request, Response.TRYING); |
| 920 | 922 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 921 | 923 | logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage()); |
| 924 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | |
| 925 | + return; | |
| 922 | 926 | } |
| 923 | 927 | String contentString = new String(request.getRawContent()); |
| 924 | 928 | // jainSip不支持y=字段, 移除移除以解析。 |
| ... | ... | @@ -973,6 +977,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 973 | 977 | responseAck(request, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 |
| 974 | 978 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 975 | 979 | logger.error("[命令发送失败] invite 不支持的媒体格式: {}", e.getMessage()); |
| 980 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | |
| 981 | + return; | |
| 976 | 982 | } |
| 977 | 983 | return; |
| 978 | 984 | } |
| ... | ... | @@ -987,6 +993,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 987 | 993 | responseAck(request, Response.BUSY_HERE); |
| 988 | 994 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 989 | 995 | logger.error("[命令发送失败] invite 未找到可用的zlm: {}", e.getMessage()); |
| 996 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | |
| 990 | 997 | } |
| 991 | 998 | return; |
| 992 | 999 | } |
| ... | ... | @@ -1000,6 +1007,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 1000 | 1007 | responseAck(request, Response.BUSY_HERE); |
| 1001 | 1008 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 1002 | 1009 | logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage()); |
| 1010 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | |
| 1011 | + return; | |
| 1003 | 1012 | } |
| 1004 | 1013 | return; |
| 1005 | 1014 | } |
| ... | ... | @@ -1034,11 +1043,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 1034 | 1043 | responseAck(request, Response.GONE); |
| 1035 | 1044 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 1036 | 1045 | logger.error("[命令发送失败] 语音通话 回复410失败, {}", e.getMessage()); |
| 1046 | + return; | |
| 1037 | 1047 | } |
| 1038 | 1048 | playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); |
| 1039 | 1049 | } |
| 1040 | 1050 | } catch (SdpException e) { |
| 1041 | 1051 | logger.error("[SDP解析异常]", e); |
| 1052 | + playService.stopAudioBroadcast(device.getDeviceId(), audioBroadcastCatch.getChannelId()); | |
| 1042 | 1053 | } |
| 1043 | 1054 | } else { |
| 1044 | 1055 | logger.warn("来自无效设备/平台的请求"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
| 1 | 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 | 5 | import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatch; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.bean.AudioBroadcastCatchStatus; |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 7 | 8 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 8 | 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 | 10 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| 12 | 11 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| 13 | 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 | 14 | import gov.nist.javax.sip.message.SIPRequest; |
| 16 | 15 | import org.dom4j.Element; |
| 17 | 16 | import org.slf4j.Logger; |
| ... | ... | @@ -38,11 +37,14 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i |
| 38 | 37 | private ResponseMessageHandler responseMessageHandler; |
| 39 | 38 | |
| 40 | 39 | @Autowired |
| 41 | - private DeferredResultHolder deferredResultHolder; | |
| 40 | + private DynamicTask dynamicTask; | |
| 42 | 41 | |
| 43 | 42 | @Autowired |
| 44 | 43 | private AudioBroadcastManager audioBroadcastManager; |
| 45 | 44 | |
| 45 | + @Autowired | |
| 46 | + private IPlayService playService; | |
| 47 | + | |
| 46 | 48 | @Override |
| 47 | 49 | public void afterPropertiesSet() throws Exception { |
| 48 | 50 | responseMessageHandler.addHandler(cmdType, this); |
| ... | ... | @@ -50,33 +52,33 @@ public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent i |
| 50 | 52 | |
| 51 | 53 | @Override |
| 52 | 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 | 59 | if (!audioBroadcastManager.exit(device.getDeviceId(), channelId)) { |
| 70 | 60 | // 回复410 |
| 71 | 61 | responseAck((SIPRequest) evt.getRequest(), Response.GONE); |
| 72 | 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 | 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 | 82 | } catch (ParseException | SipException | InvalidArgumentException e) { |
| 81 | 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 | 1045 | event.call("语音广播已经开启"); |
| 1046 | 1046 | return; |
| 1047 | 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 | 1054 | cmder.audioBroadcastCmd(device, channelId, eventResultForOk -> { |
| 1056 | 1055 | // 发送成功 |
| 1057 | 1056 | AudioBroadcastCatch audioBroadcastCatch = new AudioBroadcastCatch(device.getDeviceId(), channelId, AudioBroadcastCatchStatus.Ready); |
| 1058 | - audioBroadcastManager.add(audioBroadcastCatch); | |
| 1057 | + audioBroadcastManager.update(audioBroadcastCatch); | |
| 1059 | 1058 | }, eventResultForError -> { |
| 1060 | 1059 | // 发送失败 |
| 1061 | 1060 | logger.error("语音广播发送失败: {}:{}", channelId, eventResultForError.msg); | ... | ... |