Commit d21322a93258206eb910d7ac3a70a4812fc48cbc

Authored by 648540858
1 parent 01a619f9

优化国标级联录像预览

src/main/java/com/genersoft/iot/vmp/gb28181/bean/SDPInfo.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +import javax.sdp.SessionDescription;
  4 +
  5 +public class SDPInfo {
  6 + private byte[] source;
  7 + private SessionDescription sdpSource;
  8 + private String sessionName;
  9 + private Long startTime;
  10 + private Long stopTime;
  11 + private String username;
  12 + private String address;
  13 + private String ssrc;
  14 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -453,6 +453,7 @@ public class SIPCommander implements ISIPCommander { @@ -453,6 +453,7 @@ public class SIPCommander implements ISIPCommander {
453 subscribeKey.put("app", "rtp"); 453 subscribeKey.put("app", "rtp");
454 subscribeKey.put("stream", ssrcInfo.getStream()); 454 subscribeKey.put("stream", ssrcInfo.getStream());
455 subscribeKey.put("regist", true); 455 subscribeKey.put("regist", true);
  456 + subscribeKey.put("schema", "rtmp");
456 subscribeKey.put("mediaServerId", mediaServerItem.getId()); 457 subscribeKey.put("mediaServerId", mediaServerItem.getId());
457 logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString()); 458 logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
458 subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, 459 subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
@@ -718,6 +719,7 @@ public class SIPCommander implements ISIPCommander { @@ -718,6 +719,7 @@ public class SIPCommander implements ISIPCommander {
718 if (ssrcTransaction != null) { 719 if (ssrcTransaction != null) {
719 MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId()); 720 MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
720 mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc()); 721 mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc());
  722 + mediaServerService.closeRTPServer(deviceId, channelId, ssrcTransaction.getStream());
721 streamSession.remove(deviceId, channelId, ssrcTransaction.getStream()); 723 streamSession.remove(deviceId, channelId, ssrcTransaction.getStream());
722 } 724 }
723 } catch (SipException | ParseException e) { 725 } catch (SipException | ParseException e) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -68,7 +68,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -68,7 +68,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
68 */ 68 */
69 @Override 69 @Override
70 public void process(RequestEvent evt) { 70 public void process(RequestEvent evt) {
71 - logger.debug("ACK请求: {}", ((System.currentTimeMillis()))); 71 + logger.info("ACK请求: {}", ((System.currentTimeMillis())));
72 Dialog dialog = evt.getDialog(); 72 Dialog dialog = evt.getDialog();
73 if (dialog == null) return; 73 if (dialog == null) return;
74 if (dialog.getState()== DialogState.CONFIRMED) { 74 if (dialog.getState()== DialogState.CONFIRMED) {
@@ -88,10 +88,6 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In @@ -88,10 +88,6 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
88 streamInfo = new StreamInfo(); 88 streamInfo = new StreamInfo();
89 streamInfo.setApp(sendRtpItem.getApp()); 89 streamInfo.setApp(sendRtpItem.getApp());
90 streamInfo.setStream(sendRtpItem.getStreamId()); 90 streamInfo.setStream(sendRtpItem.getStreamId());
91 - }else {  
92 - streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);  
93 - sendRtpItem.setStreamId(streamInfo.getStream());  
94 - streamInfo.setApp("rtp");  
95 } 91 }
96 redisCatchStorage.updateSendRTPSever(sendRtpItem); 92 redisCatchStorage.updateSendRTPSever(sendRtpItem);
97 logger.info(platformGbId); 93 logger.info(platformGbId);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.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.genersoft.iot.vmp.common.StreamInfo; 3 import com.genersoft.iot.vmp.common.StreamInfo;
4 import com.genersoft.iot.vmp.gb28181.bean.Device; 4 import com.genersoft.iot.vmp.gb28181.bean.Device;
  5 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
5 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 6 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
6 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 7 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
7 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 8 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
@@ -90,29 +91,31 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In @@ -90,29 +91,31 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
90 int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId); 91 int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);
91 if (totalReaderCount == 0) { 92 if (totalReaderCount == 0) {
92 logger.info(streamId + "无其它观看者,通知设备停止推流"); 93 logger.info(streamId + "无其它观看者,通知设备停止推流");
93 - cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId); 94 + cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId);
94 }else if (totalReaderCount == -1){ 95 }else if (totalReaderCount == -1){
95 logger.warn(streamId + " 查找其它观看者失败"); 96 logger.warn(streamId + " 查找其它观看者失败");
96 } 97 }
97 } 98 }
98 // 可能是设备主动停止 99 // 可能是设备主动停止
99 Device device = storager.queryVideoDeviceByChannelId(platformGbId); 100 Device device = storager.queryVideoDeviceByChannelId(platformGbId);
100 - if (device != null) {  
101 - if (sendRtpItem.isPlay()) {  
102 - StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);  
103 - if (streamInfo != null) {  
104 - redisCatchStorage.stopPlay(streamInfo); 101 + if (device != null) {
  102 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
  103 + if (sendRtpItem != null) {
  104 + if (sendRtpItem.isPlay()) {
  105 + if (streamInfo != null) {
  106 + redisCatchStorage.stopPlay(streamInfo);
  107 + }
  108 + }else {
  109 + if (streamInfo != null) {
  110 + redisCatchStorage.stopPlayback(streamInfo);
  111 + }
105 } 112 }
106 - }else {  
107 - StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(device.getDeviceId(), channelId);  
108 - if (streamInfo != null) {  
109 - redisCatchStorage.stopPlayback(streamInfo);  
110 - }  
111 - }  
112 113
113 - storager.stopPlay(device.getDeviceId(), channelId);  
114 - mediaServerService.closeRTPServer(device, channelId, streamInfo.getStream()); 114 + storager.stopPlay(device.getDeviceId(), channelId);
  115 + mediaServerService.closeRTPServer(device.getDeviceId(), channelId, streamInfo.getStream());
  116 + }
115 } 117 }
  118 +
116 } 119 }
117 } catch (SipException e) { 120 } catch (SipException e) {
118 e.printStackTrace(); 121 e.printStackTrace();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
12 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; 12 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; 13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
  15 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
15 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; 16 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
16 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 17 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
17 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 18 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -101,19 +102,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -101,19 +102,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
101 @Override 102 @Override
102 public void process(RequestEvent evt) { 103 public void process(RequestEvent evt) {
103 // Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令 104 // Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
104 - Long startTimeForInvite = System.currentTimeMillis();  
105 try { 105 try {
106 Request request = evt.getRequest(); 106 Request request = evt.getRequest();
107 SipURI sipURI = (SipURI) request.getRequestURI(); 107 SipURI sipURI = (SipURI) request.getRequestURI();
108 String channelId = sipURI.getUser(); 108 String channelId = sipURI.getUser();
109 - String requesterId = null;  
110 -  
111 - FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); 109 + String requesterId = SipUtils.getUserIdFromFromHeader(request);
112 CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME); 110 CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
113 - AddressImpl address = (AddressImpl) fromHeader.getAddress();  
114 - SipUri uri = (SipUri) address.getURI();  
115 - requesterId = uri.getUser();  
116 -  
117 if (requesterId == null || channelId == null) { 111 if (requesterId == null || channelId == null) {
118 logger.info("无法从FromHeader的Address中获取到平台id,返回400"); 112 logger.info("无法从FromHeader的Address中获取到平台id,返回400");
119 responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误 113 responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误
@@ -122,7 +116,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -122,7 +116,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
122 116
123 // 查询请求是否来自上级平台\设备 117 // 查询请求是否来自上级平台\设备
124 ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId); 118 ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
125 - if (platform != null) { 119 + if (platform == null) {
  120 + inviteFromDeviceHandle(evt, requesterId);
  121 + }else {
126 // 查询平台下是否有该通道 122 // 查询平台下是否有该通道
127 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); 123 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
128 GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId); 124 GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
@@ -141,7 +137,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -141,7 +137,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
141 mediaServerItem = mediaServerService.getOne(mediaServerId); 137 mediaServerItem = mediaServerService.getOne(mediaServerId);
142 if (mediaServerItem == null) { 138 if (mediaServerItem == null) {
143 logger.info("[ app={}, stream={} ]找不到zlm {},返回410",gbStream.getApp(), gbStream.getStream(), mediaServerId); 139 logger.info("[ app={}, stream={} ]找不到zlm {},返回410",gbStream.getApp(), gbStream.getStream(), mediaServerId);
144 - responseAck(evt, Response.GONE, "media server not found"); 140 + responseAck(evt, Response.GONE);
145 return; 141 return;
146 } 142 }
147 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); 143 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
@@ -197,7 +193,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -197,7 +193,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
197 // 查看是否支持PS 负载96 193 // 查看是否支持PS 负载96
198 //String ip = null; 194 //String ip = null;
199 int port = -1; 195 int port = -1;
200 - //boolean recvonly = false;  
201 boolean mediaTransmissionTCP = false; 196 boolean mediaTransmissionTCP = false;
202 Boolean tcpActive = null; 197 Boolean tcpActive = null;
203 for (Object description : mediaDescriptions) { 198 for (Object description : mediaDescriptions) {
@@ -233,7 +228,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -233,7 +228,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
233 } 228 }
234 String username = sdp.getOrigin().getUsername(); 229 String username = sdp.getOrigin().getUsername();
235 String addressStr = sdp.getOrigin().getAddress(); 230 String addressStr = sdp.getOrigin().getAddress();
236 - //String sessionName = sdp.getSessionName().getValue();  
237 logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc); 231 logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc);
238 Device device = null; 232 Device device = null;
239 // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标 233 // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标
@@ -271,8 +265,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -271,8 +265,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
271 Long finalStartTime = startTime; 265 Long finalStartTime = startTime;
272 Long finalStopTime = stopTime; 266 Long finalStopTime = stopTime;
273 ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON)->{ 267 ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON)->{
274 - logger.info("[上级点播]收到下级开始点播订阅, {}/{}", sendRtpItem.getApp(), sendRtpItem.getStreamId());  
275 - // if (sendRtpItem == null) return; 268 + logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", sendRtpItem.getApp(), sendRtpItem.getStreamId());
  269 + // * 0 等待设备推流上来
  270 + // * 1 下级已经推流,等待上级平台回复ack
  271 + // * 2 推流中
276 sendRtpItem.setStatus(1); 272 sendRtpItem.setStatus(1);
277 redisCatchStorage.updateSendRTPSever(sendRtpItem); 273 redisCatchStorage.updateSendRTPSever(sendRtpItem);
278 274
@@ -301,9 +297,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -301,9 +297,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
301 } catch (ParseException e) { 297 } catch (ParseException e) {
302 e.printStackTrace(); 298 e.printStackTrace();
303 } 299 }
304 - if ("Playback".equals(sessionName) && responseJSON != null) {  
305 - playService.onPublishHandlerForPlayBack(finalMediaServerItem, responseJSON, finalDevice.getDeviceId(), channelId, null);  
306 - }  
307 }; 300 };
308 SipSubscribe.Event errorEvent = ((event) -> { 301 SipSubscribe.Event errorEvent = ((event) -> {
309 // 未知错误。直接转发设备点播的错误 302 // 未知错误。直接转发设备点播的错误
@@ -319,10 +312,29 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -319,10 +312,29 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
319 }); 312 });
320 if ("Playback".equals(sessionName)) { 313 if ("Playback".equals(sessionName)) {
321 sendRtpItem.setPlay(false); 314 sendRtpItem.setPlay(false);
322 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, sendRtpItem.getSsrc(), true);  
323 sendRtpItem.setStreamId(ssrc); 315 sendRtpItem.setStreamId(ssrc);
324 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 316 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
325 - commander.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, format.format(start), format.format(end), hookEvent, errorEvent); 317 + playService.playBack(device.getDeviceId(), channelId, format.format(start), format.format(end),result -> {
  318 + if (result.getCode() != 0){
  319 + logger.warn("录像回放失败");
  320 + if (result.getEvent() != null) {
  321 + errorEvent.response(result.getEvent());
  322 + }
  323 + try {
  324 + responseAck(evt, Response.REQUEST_TIMEOUT);
  325 + } catch (SipException e) {
  326 + e.printStackTrace();
  327 + } catch (InvalidArgumentException e) {
  328 + e.printStackTrace();
  329 + } catch (ParseException e) {
  330 + e.printStackTrace();
  331 + }
  332 + }else {
  333 + if (result.getMediaServerItem() != null) {
  334 + hookEvent.response(result.getMediaServerItem(), result.getResponse());
  335 + }
  336 + }
  337 + });
326 }else { 338 }else {
327 sendRtpItem.setPlay(true); 339 sendRtpItem.setPlay(true);
328 StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId); 340 StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
@@ -333,7 +345,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -333,7 +345,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
333 sendRtpItem.setPlay(false); 345 sendRtpItem.setPlay(false);
334 playService.play(mediaServerItem,device.getDeviceId(), channelId, hookEvent,errorEvent); 346 playService.play(mediaServerItem,device.getDeviceId(), channelId, hookEvent,errorEvent);
335 }else { 347 }else {
336 - sendRtpItem.setStreamId(streamInfo.getStreamId()); 348 + sendRtpItem.setStreamId(streamInfo.getStream());
337 hookEvent.response(mediaServerItem, null); 349 hookEvent.response(mediaServerItem, null);
338 } 350 }
339 } 351 }
@@ -379,72 +391,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -379,72 +391,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
379 } 391 }
380 } 392 }
381 393
382 - } else {  
383 - // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)  
384 - Device device = redisCatchStorage.getDevice(requesterId);  
385 - if (device != null) {  
386 - logger.info("收到设备" + requesterId + "的语音广播Invite请求");  
387 - responseAck(evt, Response.TRYING);  
388 -  
389 - String contentString = new String(request.getRawContent());  
390 - // jainSip不支持y=字段, 移除移除以解析。  
391 - String substring = contentString;  
392 - String ssrc = "0000000404";  
393 - int ssrcIndex = contentString.indexOf("y=");  
394 - if (ssrcIndex > 0) {  
395 - substring = contentString.substring(0, ssrcIndex);  
396 - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);  
397 - }  
398 - ssrcIndex = substring.indexOf("f=");  
399 - if (ssrcIndex > 0) {  
400 - substring = contentString.substring(0, ssrcIndex);  
401 - }  
402 - SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);  
403 -  
404 - // 获取支持的格式  
405 - Vector mediaDescriptions = sdp.getMediaDescriptions(true);  
406 - // 查看是否支持PS 负载96  
407 - int port = -1;  
408 - //boolean recvonly = false;  
409 - boolean mediaTransmissionTCP = false;  
410 - Boolean tcpActive = null;  
411 - for (int i = 0; i < mediaDescriptions.size(); i++) {  
412 - MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);  
413 - Media media = mediaDescription.getMedia();  
414 -  
415 - Vector mediaFormats = media.getMediaFormats(false);  
416 - if (mediaFormats.contains("8")) {  
417 - port = media.getMediaPort();  
418 - String protocol = media.getProtocol();  
419 - // 区分TCP发流还是udp, 当前默认udp  
420 - if ("TCP/RTP/AVP".equals(protocol)) {  
421 - String setup = mediaDescription.getAttribute("setup");  
422 - if (setup != null) {  
423 - mediaTransmissionTCP = true;  
424 - if ("active".equals(setup)) {  
425 - tcpActive = true;  
426 - } else if ("passive".equals(setup)) {  
427 - tcpActive = false;  
428 - }  
429 - }  
430 - }  
431 - break;  
432 - }  
433 - }  
434 - if (port == -1) {  
435 - logger.info("不支持的媒体格式,返回415");  
436 - // 回复不支持的格式  
437 - responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415  
438 - return;  
439 - }  
440 - String username = sdp.getOrigin().getUsername();  
441 - String addressStr = sdp.getOrigin().getAddress();  
442 - logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc);  
443 -  
444 - } else {  
445 - logger.warn("来自无效设备/平台的请求");  
446 - responseAck(evt, Response.BAD_REQUEST);  
447 - }  
448 } 394 }
449 395
450 } catch (SipException | InvalidArgumentException | ParseException e) { 396 } catch (SipException | InvalidArgumentException | ParseException e) {
@@ -457,4 +403,74 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -457,4 +403,74 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
457 e.printStackTrace(); 403 e.printStackTrace();
458 } 404 }
459 } 405 }
  406 +
  407 + public void inviteFromDeviceHandle(RequestEvent evt, String requesterId) throws InvalidArgumentException, ParseException, SipException, SdpException {
  408 +
  409 + // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
  410 + Device device = redisCatchStorage.getDevice(requesterId);
  411 + Request request = evt.getRequest();
  412 + if (device != null) {
  413 + logger.info("收到设备" + requesterId + "的语音广播Invite请求");
  414 + responseAck(evt, Response.TRYING);
  415 +
  416 + String contentString = new String(request.getRawContent());
  417 + // jainSip不支持y=字段, 移除移除以解析。
  418 + String substring = contentString;
  419 + String ssrc = "0000000404";
  420 + int ssrcIndex = contentString.indexOf("y=");
  421 + if (ssrcIndex > 0) {
  422 + substring = contentString.substring(0, ssrcIndex);
  423 + ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  424 + }
  425 + ssrcIndex = substring.indexOf("f=");
  426 + if (ssrcIndex > 0) {
  427 + substring = contentString.substring(0, ssrcIndex);
  428 + }
  429 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  430 +
  431 + // 获取支持的格式
  432 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  433 + // 查看是否支持PS 负载96
  434 + int port = -1;
  435 + //boolean recvonly = false;
  436 + boolean mediaTransmissionTCP = false;
  437 + Boolean tcpActive = null;
  438 + for (int i = 0; i < mediaDescriptions.size(); i++) {
  439 + MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
  440 + Media media = mediaDescription.getMedia();
  441 +
  442 + Vector mediaFormats = media.getMediaFormats(false);
  443 + if (mediaFormats.contains("8")) {
  444 + port = media.getMediaPort();
  445 + String protocol = media.getProtocol();
  446 + // 区分TCP发流还是udp, 当前默认udp
  447 + if ("TCP/RTP/AVP".equals(protocol)) {
  448 + String setup = mediaDescription.getAttribute("setup");
  449 + if (setup != null) {
  450 + mediaTransmissionTCP = true;
  451 + if ("active".equals(setup)) {
  452 + tcpActive = true;
  453 + } else if ("passive".equals(setup)) {
  454 + tcpActive = false;
  455 + }
  456 + }
  457 + }
  458 + break;
  459 + }
  460 + }
  461 + if (port == -1) {
  462 + logger.info("不支持的媒体格式,返回415");
  463 + // 回复不支持的格式
  464 + responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
  465 + return;
  466 + }
  467 + String username = sdp.getOrigin().getUsername();
  468 + String addressStr = sdp.getOrigin().getAddress();
  469 + logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc);
  470 +
  471 + } else {
  472 + logger.warn("来自无效设备/平台的请求");
  473 + responseAck(evt, Response.BAD_REQUEST);
  474 + }
  475 + }
460 } 476 }
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -48,7 +48,7 @@ public interface IMediaServerService { @@ -48,7 +48,7 @@ public interface IMediaServerService {
48 48
49 SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean isPlayback); 49 SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean isPlayback);
50 50
51 - void closeRTPServer(Device device, String channelId, String ssrc); 51 + void closeRTPServer(String deviceId, String channelId, String ssrc);
52 52
53 void clearRTPServer(MediaServerItem mediaServerItem); 53 void clearRTPServer(MediaServerItem mediaServerItem);
54 54
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java
1 package com.genersoft.iot.vmp.service.bean; 1 package com.genersoft.iot.vmp.service.bean;
2 2
3 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 3 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  4 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
4 5
5 public interface PlayBackCallback { 6 public interface PlayBackCallback {
6 7
7 - void call(RequestMessage msg); 8 + void call(PlayBackResult<RequestMessage> msg);
8 9
9 } 10 }
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.bean;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  5 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  6 +
  7 +import javax.sip.RequestEvent;
  8 +
  9 +public class PlayBackResult<T> {
  10 + private int code;
  11 + private T data;
  12 + private MediaServerItem mediaServerItem;
  13 + private JSONObject response;
  14 + private SipSubscribe.EventResult event;
  15 +
  16 + public int getCode() {
  17 + return code;
  18 + }
  19 +
  20 + public void setCode(int code) {
  21 + this.code = code;
  22 + }
  23 +
  24 + public T getData() {
  25 + return data;
  26 + }
  27 +
  28 + public void setData(T data) {
  29 + this.data = data;
  30 + }
  31 +
  32 + public MediaServerItem getMediaServerItem() {
  33 + return mediaServerItem;
  34 + }
  35 +
  36 + public void setMediaServerItem(MediaServerItem mediaServerItem) {
  37 + this.mediaServerItem = mediaServerItem;
  38 + }
  39 +
  40 + public JSONObject getResponse() {
  41 + return response;
  42 + }
  43 +
  44 + public void setResponse(JSONObject response) {
  45 + this.response = response;
  46 + }
  47 +
  48 + public SipSubscribe.EventResult getEvent() {
  49 + return event;
  50 + }
  51 +
  52 + public void setEvent(SipSubscribe.EventResult event) {
  53 + this.event = event;
  54 + }
  55 +}
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -160,16 +160,16 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -160,16 +160,16 @@ public class MediaServerServiceImpl implements IMediaServerService {
160 } 160 }
161 161
162 @Override 162 @Override
163 - public void closeRTPServer(Device device, String channelId, String stream) {  
164 - String mediaServerId = streamSession.getMediaServerId(device.getDeviceId(), channelId, stream);  
165 - String ssrc = streamSession.getSSRC(device.getDeviceId(), channelId, stream); 163 + public void closeRTPServer(String deviceId, String channelId, String stream) {
  164 + String mediaServerId = streamSession.getMediaServerId(deviceId, channelId, stream);
  165 + String ssrc = streamSession.getSSRC(deviceId, channelId, stream);
166 MediaServerItem mediaServerItem = this.getOne(mediaServerId); 166 MediaServerItem mediaServerItem = this.getOne(mediaServerId);
167 if (mediaServerItem != null) { 167 if (mediaServerItem != null) {
168 - String streamId = String.format("%s_%s", device.getDeviceId(), channelId); 168 + String streamId = String.format("%s_%s", deviceId, channelId);
169 zlmrtpServerFactory.closeRTPServer(mediaServerItem, streamId); 169 zlmrtpServerFactory.closeRTPServer(mediaServerItem, streamId);
170 releaseSsrc(mediaServerItem, ssrc); 170 releaseSsrc(mediaServerItem, ssrc);
171 } 171 }
172 - streamSession.remove(device.getDeviceId(), channelId, stream); 172 + streamSession.remove(deviceId, channelId, stream);
173 } 173 }
174 174
175 @Override 175 @Override
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -17,6 +17,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; @@ -17,6 +17,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
17 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.IMediaServerService; 18 import com.genersoft.iot.vmp.service.IMediaServerService;
19 import com.genersoft.iot.vmp.service.bean.PlayBackCallback; 19 import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
  20 +import com.genersoft.iot.vmp.service.bean.PlayBackResult;
20 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 21 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
21 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 22 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
22 import com.genersoft.iot.vmp.storager.IVideoManagerStorager; 23 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
@@ -115,11 +116,8 @@ public class PlayServiceImpl implements IPlayService { @@ -115,11 +116,8 @@ public class PlayServiceImpl implements IPlayService {
115 msg.setData(wvpResult); 116 msg.setData(wvpResult);
116 // 点播超时回复BYE 117 // 点播超时回复BYE
117 cmder.streamByeCmd(device.getDeviceId(), channelId, streamInfo.getStream()); 118 cmder.streamByeCmd(device.getDeviceId(), channelId, streamInfo.getStream());
118 - // 释放rtpserver  
119 - mediaServerService.closeRTPServer(playResult.getDevice(), channelId, streamInfo.getStream());  
120 // 回复之前所有的点播请求 119 // 回复之前所有的点播请求
121 resultHolder.invokeAllResult(msg); 120 resultHolder.invokeAllResult(msg);
122 - // TODO 释放ssrc  
123 }); 121 });
124 result.onCompletion(()->{ 122 result.onCompletion(()->{
125 // 点播结束时调用截图接口 123 // 点播结束时调用截图接口
@@ -173,7 +171,10 @@ public class PlayServiceImpl implements IPlayService { @@ -173,7 +171,10 @@ public class PlayServiceImpl implements IPlayService {
173 WVPResult wvpResult = new WVPResult(); 171 WVPResult wvpResult = new WVPResult();
174 wvpResult.setCode(-1); 172 wvpResult.setCode(-1);
175 // 点播返回sip错误 173 // 点播返回sip错误
176 - mediaServerService.closeRTPServer(playResult.getDevice(), channelId, ssrcInfo.getStream()); 174 + mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream());
  175 + // 释放ssrc
  176 + mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
  177 + streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
177 wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); 178 wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));
178 msg.setData(wvpResult); 179 msg.setData(wvpResult);
179 resultHolder.invokeAllResult(msg); 180 resultHolder.invokeAllResult(msg);
@@ -222,7 +223,10 @@ public class PlayServiceImpl implements IPlayService { @@ -222,7 +223,10 @@ public class PlayServiceImpl implements IPlayService {
222 logger.info("收到订阅消息: " + response.toJSONString()); 223 logger.info("收到订阅消息: " + response.toJSONString());
223 onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid); 224 onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid);
224 }, (event) -> { 225 }, (event) -> {
225 - mediaServerService.closeRTPServer(playResult.getDevice(), channelId, ssrcInfo.getStream()); 226 + mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream());
  227 + // 释放ssrc
  228 + mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
  229 + streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
226 WVPResult wvpResult = new WVPResult(); 230 WVPResult wvpResult = new WVPResult();
227 wvpResult.setCode(-1); 231 wvpResult.setCode(-1);
228 wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg)); 232 wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));
@@ -240,7 +244,7 @@ public class PlayServiceImpl implements IPlayService { @@ -240,7 +244,7 @@ public class PlayServiceImpl implements IPlayService {
240 RequestMessage msg = new RequestMessage(); 244 RequestMessage msg = new RequestMessage();
241 msg.setId(uuid); 245 msg.setId(uuid);
242 msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId); 246 msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId);
243 - StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId); 247 + StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
244 if (streamInfo != null) { 248 if (streamInfo != null) {
245 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); 249 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
246 if (deviceChannel != null) { 250 if (deviceChannel != null) {
@@ -298,9 +302,12 @@ public class PlayServiceImpl implements IPlayService { @@ -298,9 +302,12 @@ public class PlayServiceImpl implements IPlayService {
298 RequestMessage msg = new RequestMessage(); 302 RequestMessage msg = new RequestMessage();
299 msg.setId(uuid); 303 msg.setId(uuid);
300 msg.setKey(key); 304 msg.setKey(key);
  305 + PlayBackResult<RequestMessage> playBackResult = new PlayBackResult<>();
301 result.onTimeout(()->{ 306 result.onTimeout(()->{
302 msg.setData("回放超时"); 307 msg.setData("回放超时");
303 - callback.call(msg); 308 + playBackResult.setCode(-1);
  309 + playBackResult.setData(msg);
  310 + callback.call(playBackResult);
304 }); 311 });
305 cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> { 312 cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> {
306 logger.info("收到订阅消息: " + response.toJSONString()); 313 logger.info("收到订阅消息: " + response.toJSONString());
@@ -308,15 +315,24 @@ public class PlayServiceImpl implements IPlayService { @@ -308,15 +315,24 @@ public class PlayServiceImpl implements IPlayService {
308 if (streamInfo == null) { 315 if (streamInfo == null) {
309 logger.warn("设备回放API调用失败!"); 316 logger.warn("设备回放API调用失败!");
310 msg.setData("设备回放API调用失败!"); 317 msg.setData("设备回放API调用失败!");
311 - callback.call(msg); 318 + playBackResult.setCode(-1);
  319 + playBackResult.setData(msg);
  320 + callback.call(playBackResult);
312 return; 321 return;
313 } 322 }
314 redisCatchStorage.startPlayback(streamInfo); 323 redisCatchStorage.startPlayback(streamInfo);
315 msg.setData(JSON.toJSONString(streamInfo)); 324 msg.setData(JSON.toJSONString(streamInfo));
316 - callback.call(msg); 325 + playBackResult.setCode(0);
  326 + playBackResult.setData(msg);
  327 + playBackResult.setMediaServerItem(mediaServerItem);
  328 + playBackResult.setResponse(response);
  329 + callback.call(playBackResult);
317 }, event -> { 330 }, event -> {
318 msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg)); 331 msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
319 - callback.call(msg); 332 + playBackResult.setCode(-1);
  333 + playBackResult.setData(msg);
  334 + playBackResult.setEvent(event);
  335 + callback.call(playBackResult);
320 }); 336 });
321 return result; 337 return result;
322 } 338 }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -129,7 +129,6 @@ public class PlayController { @@ -129,7 +129,6 @@ public class PlayController {
129 //Response response = event.getResponse(); 129 //Response response = event.getResponse();
130 msg.setData(String.format("success")); 130 msg.setData(String.format("success"));
131 resultHolder.invokeAllResult(msg); 131 resultHolder.invokeAllResult(msg);
132 - mediaServerService.closeRTPServer(device, channelId, streamInfo.getStream());  
133 }); 132 });
134 133
135 if (deviceId != null || channelId != null) { 134 if (deviceId != null || channelId != null) {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
@@ -77,8 +77,8 @@ public class PlaybackController { @@ -77,8 +77,8 @@ public class PlaybackController {
77 logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); 77 logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
78 } 78 }
79 79
80 - DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, msg->{  
81 - resultHolder.invokeResult(msg); 80 + DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, wvpResult->{
  81 + resultHolder.invokeResult(wvpResult.getData());
82 }); 82 });
83 83
84 return result; 84 return result;