Commit c429a34e5390b0245da276c2c03a6116822167c3

Authored by 648540858
1 parent 490c5538

修复国标视频点播三种级联并发点播和录像下载的问题

Showing 20 changed files with 515 additions and 673 deletions
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
... ... @@ -4,7 +4,6 @@ import com.genersoft.iot.vmp.common.StreamInfo;
4 4 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 6 import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
7   -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
8 7 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
9 8 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
10 9 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
... ... @@ -109,7 +108,7 @@ public interface ISIPCommander {
109 108 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
110 109 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
111 110 */
112   - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  111 + void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
113 112  
114 113 /**
115 114 * 请求历史媒体下载
... ... @@ -121,7 +120,7 @@ public interface ISIPCommander {
121 120 * @param downloadSpeed 下载倍速参数
122 121 */
123 122 void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
124   - String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  123 + String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,
125 124 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
126 125  
127 126 /**
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -366,11 +366,11 @@ public class SIPCommander implements ISIPCommander {
366 366 */
367 367 @Override
368 368 public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
369   - String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  369 + String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent,
370 370 SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
371 371  
372 372  
373   - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getSdpIp(), mediaServerItem.getIp(), ssrcInfo.getPort());
  373 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
374 374 String sdpIp;
375 375 if (!ObjectUtils.isEmpty(device.getSdpIp())) {
376 376 sdpIp = device.getSdpIp();
... ... @@ -443,8 +443,7 @@ public class SIPCommander implements ISIPCommander {
443 443 // 添加订阅
444 444 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
445 445 if (hookEvent != null) {
446   - InviteStreamInfo inviteStreamInfo = new InviteStreamInfo(mediaServerItemInUse, json,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), "rtp", ssrcInfo.getStream());
447   - hookEvent.call(inviteStreamInfo);
  446 + hookEvent.response(mediaServerItemInUse, json);
448 447 }
449 448 subscribe.removeSubscribe(hookSubscribe);
450 449 });
... ... @@ -456,9 +455,6 @@ public class SIPCommander implements ISIPCommander {
456 455 streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK);
457 456 okEvent.response(event);
458 457 });
459   - if (inviteStreamCallback != null) {
460   - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), "rtp", ssrcInfo.getStream()));
461   - }
462 458 }
463 459  
464 460 /**
... ... @@ -473,10 +469,10 @@ public class SIPCommander implements ISIPCommander {
473 469 @Override
474 470 public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
475 471 String startTime, String endTime, int downloadSpeed,
476   - InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  472 + ZlmHttpHookSubscribe.Event hookEvent,
477 473 SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
478 474  
479   - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getSdpIp(), mediaServerItem.getIp(), ssrcInfo.getPort());
  475 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
480 476 String sdpIp;
481 477 if (!ObjectUtils.isEmpty(device.getSdpIp())) {
482 478 sdpIp = device.getSdpIp();
... ... @@ -550,7 +546,7 @@ public class SIPCommander implements ISIPCommander {
550 546 String callId= newCallIdHeader.getCallId();
551 547 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
552 548 logger.debug("sipc 添加订阅===callId {}",callId);
553   - hookEvent.call(new InviteStreamInfo(mediaServerItem, json,callId, "rtp", ssrcInfo.getStream()));
  549 + hookEvent.response(mediaServerItemInUse, json);
554 550 subscribe.removeSubscribe(hookSubscribe);
555 551 hookSubscribe.getContent().put("regist", false);
556 552 hookSubscribe.getContent().put("schema", "rtsp");
... ... @@ -568,9 +564,6 @@ public class SIPCommander implements ISIPCommander {
568 564 });
569 565  
570 566 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
571   - if (inviteStreamCallback != null) {
572   - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null,callId, "rtp", ssrcInfo.getStream()));
573   - }
574 567  
575 568 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
576 569 ResponseEvent responseEvent = (ResponseEvent) event.event;
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
... ... @@ -356,7 +356,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
356 356 }else {
357 357 streamTypeStr = "UDP";
358 358 }
359   - logger.info("[上级点播] 平台:{}, 通道:{}, 收流地址:{}:{},收流方式:{}, ssrc:{}", username, channelId, addressStr, port, streamTypeStr, ssrc);
  359 + logger.info("[上级Invite] {}, 平台:{}, 通道:{}, 收流地址:{}:{},收流方式:{}, ssrc:{}", sessionName, username, channelId, addressStr, port, streamTypeStr, ssrc);
360 360 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
361 361 device.getDeviceId(), channelId, mediaTransmissionTCP, platform.isRtcp());
362 362  
... ... @@ -380,7 +380,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
380 380 InviteErrorCallback<Object> hookEvent = (code, msg, data) -> {
381 381 StreamInfo streamInfo = (StreamInfo)data;
382 382 MediaServerItem mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
383   - logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", streamInfo.getApp(), streamInfo.getStream());
  383 + logger.info("[上级Invite]下级已经开始推流。 回复200OK(SDP), {}/{}", streamInfo.getApp(), streamInfo.getStream());
384 384 // * 0 等待设备推流上来
385 385 // * 1 下级已经推流,等待上级平台回复ack
386 386 // * 2 推流中
... ... @@ -443,22 +443,16 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
443 443 // 写入redis, 超时时回复
444 444 redisCatchStorage.updateSendRTPSever(sendRtpItem);
445 445 playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
446   - DateUtil.formatter.format(end), null, result -> {
447   - if (result.getCode() != 0) {
448   - logger.warn("录像回放失败");
449   - if (result.getEvent() != null) {
450   -// errorEvent.response(result.getEvent());
451   - }
  446 + DateUtil.formatter.format(end),
  447 + (code, msg, data) -> {
  448 + if (code == InviteErrorCode.SUCCESS.getCode()){
  449 + hookEvent.run(code, msg, data);
  450 + }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){
  451 + logger.info("[录像回放]超时, 用户:{}, 通道:{}", username, channelId);
452 452 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
453   - try {
454   - responseAck(request, Response.REQUEST_TIMEOUT);
455   - } catch (SipException | InvalidArgumentException | ParseException e) {
456   - logger.error("[命令发送失败] 国标级联 录像回放 发送REQUEST_TIMEOUT: {}", e.getMessage());
457   - }
458   - } else {
459   - if (result.getMediaServerItem() != null) {
460   -// hookEvent.response(result.getMediaServerItem(), result.getResponse());
461   - }
  453 + errorEvent.run(code, msg, data);
  454 + }else {
  455 + errorEvent.run(code, msg, data);
462 456 }
463 457 });
464 458 } else {
... ... @@ -477,6 +471,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
477 471 }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){
478 472 logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId);
479 473 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
  474 + errorEvent.run(code, msg, data);
480 475 }else {
481 476 errorEvent.run(code, msg, data);
482 477 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
... ... @@ -80,7 +80,6 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
80 80 public void process(RequestEvent evt) {
81 81 try {
82 82 RequestEventExt evtExt = (RequestEventExt) evt;
83   - String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();
84 83  
85 84 SIPRequest request = (SIPRequest)evt.getRequest();
86 85 Response response = null;
... ... @@ -91,12 +90,13 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
91 90 AddressImpl address = (AddressImpl) fromHeader.getAddress();
92 91 SipUri uri = (SipUri) address.getURI();
93 92 String deviceId = uri.getUser();
94   - logger.info("[注册请求] 设备:{}, 开始处理: {}", deviceId, requestAddress);
  93 +
95 94 Device device = deviceService.getDevice(deviceId);
96 95  
97 96 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,
98 97 userSetting.getSipUseSourceIpAsRemoteAddress());
99   - logger.info("[注册请求] 设备:{}, 远程地址为: {}:{}", deviceId, remoteAddressInfo.getIp(), remoteAddressInfo.getPort());
  98 + String requestAddress = remoteAddressInfo.getIp() + ":" + remoteAddressInfo.getPort();
  99 + logger.info("[注册请求] 设备:{}, 开始处理: {}", deviceId, requestAddress);
100 100 if (device != null &&
101 101 device.getSipTransactionInfo() != null &&
102 102 request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info;
2 2  
3   -import com.genersoft.iot.vmp.common.StreamInfo;
  3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 5 import com.genersoft.iot.vmp.gb28181.bean.*;
5 6 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 7 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
... ... @@ -9,6 +10,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
9 10 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
10 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
11 12 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  13 +import com.genersoft.iot.vmp.service.IInviteStreamService;
12 14 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13 15 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
14 16 import gov.nist.javax.sip.message.SIPRequest;
... ... @@ -17,10 +19,12 @@ import org.slf4j.LoggerFactory;
17 19 import org.springframework.beans.factory.InitializingBean;
18 20 import org.springframework.beans.factory.annotation.Autowired;
19 21 import org.springframework.stereotype.Component;
  22 +
20 23 import javax.sip.InvalidArgumentException;
21 24 import javax.sip.RequestEvent;
22 25 import javax.sip.SipException;
23   -import javax.sip.header.*;
  26 +import javax.sip.header.CallIdHeader;
  27 +import javax.sip.header.ContentTypeHeader;
24 28 import javax.sip.message.Response;
25 29 import java.text.ParseException;
26 30  
... ... @@ -44,6 +48,9 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I
44 48 private IRedisCatchStorage redisCatchStorage;
45 49  
46 50 @Autowired
  51 + private IInviteStreamService inviteStreamService;
  52 +
  53 + @Autowired
47 54 private IVideoManagerStorage storager;
48 55  
49 56 @Autowired
... ... @@ -103,27 +110,30 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I
103 110 if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) {
104 111 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
105 112 String streamId = sendRtpItem.getStreamId();
106   - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
107   - if (null == streamInfo) {
  113 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  114 + if (null == inviteInfo) {
108 115 responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found");
109 116 return;
110 117 }
111   - Device device1 = storager.queryVideoDevice(streamInfo.getDeviceID());
112   - cmder.playbackControlCmd(device1,streamInfo,new String(evt.getRequest().getRawContent()),eventResult -> {
113   - // 失败的回复
114   - try {
115   - responseAck(request, eventResult.statusCode, eventResult.msg);
116   - } catch (SipException | InvalidArgumentException | ParseException e) {
117   - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
118   - }
119   - }, eventResult -> {
120   - // 成功的回复
121   - try {
122   - responseAck(request, eventResult.statusCode);
123   - } catch (SipException | InvalidArgumentException | ParseException e) {
124   - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
125   - }
126   - });
  118 + Device device1 = storager.queryVideoDevice(inviteInfo.getDeviceId());
  119 + if (inviteInfo.getStreamInfo() != null) {
  120 + cmder.playbackControlCmd(device1,inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()),eventResult -> {
  121 + // 失败的回复
  122 + try {
  123 + responseAck(request, eventResult.statusCode, eventResult.msg);
  124 + } catch (SipException | InvalidArgumentException | ParseException e) {
  125 + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
  126 + }
  127 + }, eventResult -> {
  128 + // 成功的回复
  129 + try {
  130 + responseAck(request, eventResult.statusCode);
  131 + } catch (SipException | InvalidArgumentException | ParseException e) {
  132 + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
  133 + }
  134 + });
  135 + }
  136 +
127 137 }
128 138 }
129 139 } catch (SipException e) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
2 2  
3   -import com.genersoft.iot.vmp.common.StreamInfo;
  3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
4 5 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 7 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
... ... @@ -15,6 +16,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.
15 16 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
16 17 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
17 18 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  19 +import com.genersoft.iot.vmp.service.IInviteStreamService;
18 20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
19 21 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
20 22 import gov.nist.javax.sip.message.SIPRequest;
... ... @@ -64,6 +66,12 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
64 66 @Autowired
65 67 private ZlmHttpHookSubscribe subscribe;
66 68  
  69 + @Autowired
  70 + private IInviteStreamService inviteStreamService;
  71 +
  72 + @Autowired
  73 + private VideoStreamSessionManager streamSession;
  74 +
67 75 @Override
68 76 public void afterPropertiesSet() throws Exception {
69 77 notifyMessageHandler.addHandler(cmdType, this);
... ... @@ -82,17 +90,15 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
82 90 String NotifyType =getText(rootElement, "NotifyType");
83 91 if ("121".equals(NotifyType)){
84 92 logger.info("[录像流]推送完毕,收到关流通知");
85   - // 查询是设备
86   - StreamInfo streamInfo = redisCatchStorage.queryDownload(null, null, null, callIdHeader.getCallId());
87   - if (streamInfo != null) {
88   - // 设置进度100%
89   - streamInfo.setProgress(1);
90   - redisCatchStorage.startDownload(streamInfo, callIdHeader.getCallId());
91   - }
92 93  
93   - // 先从会话内查找
94   - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
95   - if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题
  94 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
  95 + if (ssrcTransaction != null) {
  96 + logger.info("[录像流]推送完毕,关流通知, device: {}, channelId: {}", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId());
  97 + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  98 + if (inviteInfo.getStreamInfo() != null) {
  99 + inviteInfo.getStreamInfo().setProgress(1);
  100 + inviteStreamService.updateInviteInfo(inviteInfo);
  101 + }
96 102  
97 103 try {
98 104 cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId());
... ... @@ -117,6 +123,8 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
117 123 logger.error("[命令发送失败] 国标级联 录像播放完毕: {}", e.getMessage());
118 124 }
119 125 }
  126 + }else {
  127 + logger.info("[录像流]推送完毕,关流通知, 但是未找到对应的下载信息");
120 128 }
121 129 }
122 130 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -451,6 +451,11 @@ public class ZLMHttpHookListener {
451 451 InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
452 452 // 点播
453 453 if (inviteInfo != null) {
  454 + // 录像下载
  455 + if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {
  456 + ret.put("close", false);
  457 + return ret;
  458 + }
454 459 // 收到无人观看说明流也没有在往上级推送
455 460 if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {
456 461 List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(
... ... @@ -486,36 +491,6 @@ public class ZLMHttpHookListener {
486 491 storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
487 492 return ret;
488 493 }
489   - // 录像回放
490   - StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null,
491   - param.getStream(), null);
492   - if (streamInfoForPlayBackCatch != null) {
493   - if (streamInfoForPlayBackCatch.isPause()) {
494   - ret.put("close", false);
495   - } else {
496   - Device device = deviceService.getDevice(streamInfoForPlayBackCatch.getDeviceID());
497   - if (device != null) {
498   - try {
499   - cmder.streamByeCmd(device, streamInfoForPlayBackCatch.getChannelId(),
500   - streamInfoForPlayBackCatch.getStream(), null);
501   - } catch (InvalidArgumentException | ParseException | SipException |
502   - SsrcTransactionNotFoundException e) {
503   - logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage());
504   - }
505   - }
506   - redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(),
507   - streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null);
508   - }
509   - return ret;
510   - }
511   - // 录像下载
512   - StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null,
513   - param.getStream(), null);
514   - // 进行录像下载时无人观看不断流
515   - if (streamInfoForDownload != null) {
516   - ret.put("close", false);
517   - return ret;
518   - }
519 494 } else {
520 495 // 非国标流 推流/拉流代理
521 496 // 拉流代理
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
... ... @@ -293,11 +293,14 @@ public class ZLMRTPServerFactory {
293 293 if (jsonObject.getInteger("code") == 0) {
294 294 localPort = jsonObject.getInteger("port");
295 295 HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, serverItem.getId());
296   - // 订阅 zlm启动事件, 新的zlm也会从这里进入系统
297 296 hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout,
298 297 (MediaServerItem mediaServerItem, JSONObject response)->{
299 298 logger.info("[上级点播] {}->监听端口到期继续保持监听", ssrc);
300   - keepPort(serverItem, ssrc);
  299 + int port = keepPort(serverItem, ssrc);
  300 + if (port == 0) {
  301 + logger.info("[上级点播] {}->监听端口失败,移除监听", ssrc);
  302 + hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
  303 + }
301 304 });
302 305 logger.info("[上级点播] {}->监听端口: {}", ssrc, localPort);
303 306 }else {
... ...
src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java
... ... @@ -60,4 +60,9 @@ public interface IInviteStreamService {
60 60 * 调用一个invite回调
61 61 */
62 62 void call(InviteSessionType type, String deviceId, String channelId, String stream, int code, String msg, Object data);
  63 +
  64 + /**
  65 + * 清空一个设备的所有invite信息
  66 + */
  67 + void clearInviteInfo(String deviceId);
63 68 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
... ... @@ -3,10 +3,8 @@ package com.genersoft.iot.vmp.service;
3 3 import com.genersoft.iot.vmp.common.StreamInfo;
4 4 import com.genersoft.iot.vmp.conf.exception.ServiceException;
5 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
6   -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
7 6 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
8 7 import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
9   -import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
10 8 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
11 9  
12 10 import javax.sip.InvalidArgumentException;
... ... @@ -29,13 +27,13 @@ public interface IPlayService {
29 27 */
30 28 MediaServerItem getNewMediaServerItemHasAssist(Device device);
31 29  
32   - void playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback);
33   - void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
  30 + void playBack(String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
  31 + void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
34 32  
35 33 void zlmServerOffline(String mediaServerId);
36 34  
37   - void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback);
38   - void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
  35 + void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
  36 + void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
39 37  
40 38 StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
41 39  
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java
... ... @@ -5,7 +5,7 @@ package com.genersoft.iot.vmp.service.bean;
5 5 */
6 6 public enum InviteErrorCode {
7 7 SUCCESS(0, "成功"),
8   - ERROR_FOR_SIGNALLING_TIMEOUT(-1, "点播超时"),
  8 + ERROR_FOR_SIGNALLING_TIMEOUT(-1, "信令超时"),
9 9 ERROR_FOR_STREAM_TIMEOUT(-2, "收流超时"),
10 10 ERROR_FOR_RESOURCE_EXHAUSTION(-3, "资源耗尽"),
11 11 ERROR_FOR_CATCH_DATA(-4, "缓存数据异常"),
... ... @@ -14,7 +14,9 @@ public enum InviteErrorCode {
14 14 ERROR_FOR_SDP_PARSING_EXCEPTIONS(-7, "SDP信息解析失败"),
15 15 ERROR_FOR_SSRC_UNAVAILABLE(-8, "SSRC不可用"),
16 16 ERROR_FOR_RESET_SSRC(-9, "重新设置收流信息失败"),
17   - ERROR_FOR_SIP_SENDING_FAILED(-10, "命令发送失败");
  17 + ERROR_FOR_SIP_SENDING_FAILED(-10, "命令发送失败"),
  18 + ERROR_FOR_ASSIST_NOT_READY(-11, "没有可用的assist服务"),
  19 + ERROR_FOR_PARAMETER_ERROR(-13, "参数异常");
18 20  
19 21 private final int code;
20 22 private final String msg;
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
... ... @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
12 12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;
13 13 import com.genersoft.iot.vmp.service.IDeviceChannelService;
14 14 import com.genersoft.iot.vmp.service.IDeviceService;
  15 +import com.genersoft.iot.vmp.service.IInviteStreamService;
15 16 import com.genersoft.iot.vmp.service.IMediaServerService;
16 17 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
17 18 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
... ... @@ -59,6 +60,9 @@ public class DeviceServiceImpl implements IDeviceService {
59 60 private IRedisCatchStorage redisCatchStorage;
60 61  
61 62 @Autowired
  63 + private IInviteStreamService inviteStreamService;
  64 +
  65 + @Autowired
62 66 private DeviceMapper deviceMapper;
63 67  
64 68 @Autowired
... ... @@ -97,7 +101,7 @@ public class DeviceServiceImpl implements IDeviceService {
97 101 String now = DateUtil.getNow();
98 102 if (deviceInRedis != null && deviceInDb == null) {
99 103 // redis 存在脏数据
100   - redisCatchStorage.clearCatchByDeviceId(device.getDeviceId());
  104 + inviteStreamService.clearInviteInfo(device.getDeviceId());
101 105 }
102 106 device.setUpdateTime(now);
103 107 if (device.getKeepaliveIntervalTime() == 0) {
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
... ... @@ -175,4 +175,8 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
175 175 }
176 176  
177 177  
  178 + @Override
  179 + public void clearInviteInfo(String deviceId) {
  180 + removeInviteInfo(null, deviceId, null, null);
  181 + }
178 182 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
1 1 package com.genersoft.iot.vmp.service.impl;
2 2  
3   -import com.alibaba.fastjson2.JSON;
4 3 import com.alibaba.fastjson2.JSONArray;
5 4 import com.alibaba.fastjson2.JSONObject;
6 5 import com.genersoft.iot.vmp.common.InviteInfo;
... ... @@ -17,7 +16,6 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
17 16 import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
18 17 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
19 18 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
20   -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
21 19 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
22 20 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
23 21 import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
... ... @@ -28,12 +26,13 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
28 26 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
29 27 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
30 28 import com.genersoft.iot.vmp.service.*;
31   -import com.genersoft.iot.vmp.service.bean.*;
  29 +import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  30 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
  31 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
32 32 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
33 33 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
34 34 import com.genersoft.iot.vmp.utils.DateUtil;
35 35 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
36   -import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
37 36 import org.slf4j.Logger;
38 37 import org.slf4j.LoggerFactory;
39 38 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -182,6 +181,12 @@ public class PlayServiceImpl implements IPlayService {
182 181 public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
183 182 InviteErrorCallback<Object> callback) {
184 183  
  184 + if (mediaServerItem == null || ssrcInfo == null) {
  185 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  186 + InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
  187 + null);
  188 + return;
  189 + }
185 190 logger.info("[点播开始] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
186 191  
187 192 //端口获取失败的ssrcInfo 没有必要发送点播指令
... ... @@ -375,11 +380,10 @@ public class PlayServiceImpl implements IPlayService {
375 380 Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
376 381 if (!result) {
377 382 try {
378   - logger.warn("[停止点播] {}/{}", device.getDeviceId(), channelId);
  383 + logger.warn("[点播] 更新ssrc失败,停止点播 {}/{}", device.getDeviceId(), channelId);
379 384 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
380 385 } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
381 386 logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
382   - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
383 387 }
384 388  
385 389 dynamicTask.stop(timeOutTaskKey);
... ... @@ -459,11 +463,12 @@ public class PlayServiceImpl implements IPlayService {
459 463  
460 464 }
461 465  
462   - private void onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, PlayBackCallback playBackCallback) {
  466 + private StreamInfo onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String startTime, String endTime) {
463 467  
464 468 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
465   - PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>();
466 469 if (streamInfo != null) {
  470 + streamInfo.setStartTime(startTime);
  471 + streamInfo.setEndTime(endTime);
467 472 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
468 473 if (deviceChannel != null) {
469 474 deviceChannel.setStreamId(streamInfo.getStream());
... ... @@ -472,20 +477,13 @@ public class PlayServiceImpl implements IPlayService {
472 477 InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, deviceId, channelId);
473 478 if (inviteInfo != null) {
474 479 inviteInfo.setStatus(InviteSessionStatus.ok);
  480 +
475 481 inviteInfo.setStreamInfo(streamInfo);
476 482 inviteStreamService.updateInviteInfo(inviteInfo);
477 483 }
478 484  
479   - playBackResult.setCode(ErrorCode.SUCCESS.getCode());
480   - playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());
481   - playBackResult.setData(streamInfo);
482   - playBackCallback.call(playBackResult);
483   - } else {
484   - logger.warn("录像回放调用失败!");
485   - playBackResult.setCode(ErrorCode.ERROR100.getCode());
486   - playBackResult.setMsg("录像回放调用失败!");
487   - playBackCallback.call(playBackResult);
488 485 }
  486 + return streamInfo;
489 487 }
490 488  
491 489 @Override
... ... @@ -524,23 +522,24 @@ public class PlayServiceImpl implements IPlayService {
524 522  
525 523 @Override
526 524 public void playBack(String deviceId, String channelId, String startTime,
527   - String endTime, InviteStreamCallback inviteStreamCallback,
528   - PlayBackCallback callback) {
  525 + String endTime, InviteErrorCallback<Object> callback) {
529 526 Device device = storager.queryVideoDevice(deviceId);
530 527 if (device == null) {
531 528 return;
532 529 }
533 530 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
534 531 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
535   - playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback);
  532 + playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, callback);
536 533 }
537 534  
538 535 @Override
539 536 public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
540 537 String deviceId, String channelId, String startTime,
541   - String endTime, InviteStreamCallback infoCallBack,
542   - PlayBackCallback playBackCallback) {
  538 + String endTime, InviteErrorCallback<Object> callback) {
543 539 if (mediaServerItem == null || ssrcInfo == null) {
  540 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  541 + InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
  542 + null);
544 543 return;
545 544 }
546 545  
... ... @@ -548,133 +547,169 @@ public class PlayServiceImpl implements IPlayService {
548 547 if (device == null) {
549 548 throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在");
550 549 }
551   - logger.info("[回放消息] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
552   - PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>();
  550 + logger.info("[录像回放] deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
  551 + device.getDeviceId(), channelId, startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(),
  552 + ssrcInfo.getSsrc(), device.isSsrcCheck());
  553 + // 初始化redis中的invite消息状态
  554 + InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  555 + mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK,
  556 + InviteSessionStatus.ready);
  557 + inviteStreamService.updateInviteInfo(inviteInfo);
553 558 String playBackTimeOutTaskKey = UUID.randomUUID().toString();
554 559 dynamicTask.startDelay(playBackTimeOutTaskKey, () -> {
555   - logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
556   - playBackResult.setCode(ErrorCode.ERROR100.getCode());
557   - playBackResult.setMsg("回放超时");
  560 + logger.warn("[录像回放] 超时,deviceId:{} ,channelId:{}", deviceId, channelId);
  561 + inviteStreamService.removeInviteInfo(inviteInfo);
  562 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null);
558 563  
559 564 try {
560 565 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null);
561 566 } catch (InvalidArgumentException | ParseException | SipException e) {
562   - logger.error("[录像流]回放超时 发送BYE失败 {}", e.getMessage());
  567 + logger.error("[录像回放] 超时 发送BYE失败 {}", e.getMessage());
563 568 } catch (SsrcTransactionNotFoundException e) {
564 569 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
565 570 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
566 571 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
567 572 streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
568 573 }
569   - // 回复之前所有的点播请求
570   - playBackCallback.call(playBackResult);
571 574 }, userSetting.getPlayTimeout());
572 575  
573 576 SipSubscribe.Event errorEvent = event -> {
  577 + logger.info("[录像回放] 失败,{} {}", event.statusCode, event.msg);
574 578 dynamicTask.stop(playBackTimeOutTaskKey);
575   - playBackResult.setCode(ErrorCode.ERROR100.getCode());
576   - playBackResult.setMsg(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
577   - playBackResult.setEvent(event);
578   - playBackCallback.call(playBackResult);
  579 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(),
  580 + String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg), null);
  581 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  582 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
579 583 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  584 + inviteStreamService.removeInviteInfo(inviteInfo);
580 585 };
581 586  
582   - InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {
583   - logger.info("收到回放订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
  587 + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> {
  588 + logger.info("收到回放订阅消息: " + jsonObject);
584 589 dynamicTask.stop(playBackTimeOutTaskKey);
585   - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
  590 + StreamInfo streamInfo = onPublishHandlerForPlayback(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime);
586 591 if (streamInfo == null) {
587 592 logger.warn("设备回放API调用失败!");
588   - playBackResult.setCode(ErrorCode.ERROR100.getCode());
589   - playBackResult.setMsg("设备回放API调用失败!");
590   - playBackCallback.call(playBackResult);
  593 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  594 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
591 595 return;
592 596 }
593   - redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());
594   -
595   - playBackResult.setCode(ErrorCode.SUCCESS.getCode());
596   - playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());
597   - playBackResult.setData(streamInfo);
598   - playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
599   - playBackResult.setResponse(inviteStreamInfo.getResponse());
600   - playBackCallback.call(playBackResult);
  597 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  598 + logger.info("[录像回放] 成功 deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}", device.getDeviceId(), channelId, startTime, endTime);
601 599 };
602 600  
603 601 try {
604   - cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack,
  602 + cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime,
605 603 hookEvent, eventResult -> {
606   - if (eventResult.type == SipSubscribe.EventResultType.response) {
607   - ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
608   - String contentString = new String(responseEvent.getResponse().getRawContent());
609   - // 获取ssrc
610   - int ssrcIndex = contentString.indexOf("y=");
611   - // 检查是否有y字段
612   - if (ssrcIndex >= 0) {
613   - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
614   - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
615   - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
616   - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
617   - return;
618   - }
619   - logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
620   - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
621   - logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
622   -
623   - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
624   - // ssrc 不可用
625   - // 释放ssrc
  604 + inviteInfo.setStatus(InviteSessionStatus.ok);
  605 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
  606 + String contentString = new String(responseEvent.getResponse().getRawContent());
  607 + // 获取ssrc
  608 + int ssrcIndex = contentString.indexOf("y=");
  609 + // 检查是否有y字段
  610 + if (ssrcIndex >= 0) {
  611 + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  612 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  613 + // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  614 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  615 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  616 + String substring = contentString.substring(0, contentString.indexOf("y="));
  617 + try {
  618 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  619 + int port = -1;
  620 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  621 + for (Object description : mediaDescriptions) {
  622 + MediaDescription mediaDescription = (MediaDescription) description;
  623 + Media media = mediaDescription.getMedia();
  624 +
  625 + Vector mediaFormats = media.getMediaFormats(false);
  626 + if (mediaFormats.contains("96")) {
  627 + port = media.getMediaPort();
  628 + break;
  629 + }
  630 + }
  631 + logger.info("[录像回放-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  632 + JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
  633 + logger.info("[录像回放-TCP主动连接对方] 结果: {}", jsonObject);
  634 + } catch (SdpException e) {
  635 + logger.error("[录像回放-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
626 636 dynamicTask.stop(playBackTimeOutTaskKey);
  637 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
  638 + // 释放ssrc
627 639 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  640 +
628 641 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
629   - eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用";
630   - eventResult.statusCode = 400;
631   - errorEvent.response(eventResult);
632   - return;
  642 +
  643 + callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  644 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  645 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  646 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  647 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
633 648 }
  649 + }
  650 + return;
  651 + }
  652 + logger.info("[录像回放] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  653 + if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
  654 + logger.info("[录像回放] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  655 +
  656 + if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
  657 + // ssrc 不可用
  658 + logger.info("[录像回放] SSRC修正时发现ssrc不可使用 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  659 + // 释放ssrc
  660 + dynamicTask.stop(playBackTimeOutTaskKey);
  661 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  662 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  663 + callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  664 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  665 + return;
  666 + }
  667 +
  668 + // 单端口模式streamId也有变化,需要重新设置监听
  669 + if (!mediaServerItem.isRtpEnable()) {
  670 + // 添加订阅
  671 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  672 + subscribe.removeSubscribe(hookSubscribe);
  673 + String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
  674 + hookSubscribe.getContent().put("stream", stream);
  675 + inviteInfo.setStream(stream);
  676 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
  677 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  678 + dynamicTask.stop(playBackTimeOutTaskKey);
  679 + // hook响应
  680 + hookEvent.response(mediaServerItemInUse, response);
  681 + });
  682 + }
  683 + // 更新ssrc
  684 + Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
  685 + if (!result) {
  686 + try {
  687 + logger.warn("[录像回放] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);
  688 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  689 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  690 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
634 691  
635   - // 单端口模式streamId也有变化,需要重新设置监听
636   - if (!mediaServerItem.isRtpEnable()) {
637   - // 添加订阅
638   - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
639   - subscribe.removeSubscribe(hookSubscribe);
640   - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
641   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
642   - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
643   - dynamicTask.stop(playBackTimeOutTaskKey);
644   - // hook响应
645   - onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, playBackCallback);
646   - hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));
647   - });
648 692 }
649 693  
650   - // 关闭rtp server
651   - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
652   - if (result) {
653   - // 重新开启ssrc server
654   - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), true, device.getStreamModeForParam());
655   - }else {
656   - try {
657   - logger.warn("[回放消息]停止 {}/{}", device.getDeviceId(), channelId);
658   - cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
659   - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
660   - logger.error("[命令发送失败] 停止点播 停止, 发送BYE: {}", e.getMessage());
661   - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
662   - }
  694 + dynamicTask.stop(playBackTimeOutTaskKey);
  695 + // 释放ssrc
  696 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
663 697  
664   - dynamicTask.stop(playBackTimeOutTaskKey);
665   - // 释放ssrc
666   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
667   - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
668   - errorEvent.response(eventResult);
669   - eventResult.msg = "下级自定义了ssrc,重新设置收流信息失败";
670   - eventResult.statusCode = 500;
671   - errorEvent.response(eventResult);
672   - }
673   - });
  698 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  699 +
  700 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  701 + "下级自定义了ssrc,重新设置收流信息失败", null);
  702 +
  703 + }else {
  704 + ssrcInfo.setSsrc(ssrcInResponse);
  705 + inviteInfo.setSsrcInfo(ssrcInfo);
  706 + inviteInfo.setStream(ssrcInfo.getStream());
674 707 }
  708 + }else {
  709 + logger.info("[点播消息] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
675 710 }
676 711 }
677   -
  712 + inviteStreamService.updateInviteInfo(inviteInfo);
678 713 }, errorEvent);
679 714 } catch (InvalidArgumentException | SipException | ParseException e) {
680 715 logger.error("[命令发送失败] 回放: {}", e.getMessage());
... ... @@ -690,42 +725,50 @@ public class PlayServiceImpl implements IPlayService {
690 725  
691 726  
692 727 @Override
693   - public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback) {
  728 + public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) {
694 729 Device device = storager.queryVideoDevice(deviceId);
695 730 if (device == null) {
696 731 return;
697 732 }
698 733 MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device);
699 734 if (newMediaServerItem == null) {
700   - PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();
701   - downloadResult.setCode(ErrorCode.ERROR100.getCode());
702   - downloadResult.setMsg("未找到assist服务");
703   - playBackCallback.call(downloadResult);
  735 + callback.run(InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getCode(),
  736 + InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getMsg(),
  737 + null);
704 738 return;
705 739 }
706 740 SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
707   - download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, infoCallBack, playBackCallback);
  741 + download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, callback);
708 742 }
709 743  
710 744  
711 745 @Override
712   - public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
  746 + public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) {
713 747 if (mediaServerItem == null || ssrcInfo == null) {
  748 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  749 + InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
  750 + null);
714 751 return;
715 752 }
716   -
717 753 Device device = storager.queryVideoDevice(deviceId);
718 754 if (device == null) {
719   - throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "不存在");
  755 + callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
  756 + "设备:" + deviceId + "不存在",
  757 + null);
  758 + return;
720 759 }
721   - PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();
722 760 logger.info("[录像下载] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  761 + // 初始化redis中的invite消息状态
  762 + InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  763 + mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD,
  764 + InviteSessionStatus.ready);
  765 + inviteStreamService.updateInviteInfo(inviteInfo);
723 766 String downLoadTimeOutTaskKey = UUID.randomUUID().toString();
724 767 dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> {
725 768 logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
726   - downloadResult.setCode(ErrorCode.ERROR100.getCode());
727   - downloadResult.setMsg("录像下载请求超时");
728   - hookCallBack.call(downloadResult);
  769 + inviteStreamService.removeInviteInfo(inviteInfo);
  770 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(),
  771 + InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getMsg(), null);
729 772  
730 773 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
731 774 try {
... ... @@ -741,98 +784,129 @@ public class PlayServiceImpl implements IPlayService {
741 784  
742 785 SipSubscribe.Event errorEvent = event -> {
743 786 dynamicTask.stop(downLoadTimeOutTaskKey);
744   - downloadResult.setCode(ErrorCode.ERROR100.getCode());
745   - downloadResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg));
746   - downloadResult.setEvent(event);
747   - hookCallBack.call(downloadResult);
  787 + callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode(),
  788 + String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg), null);
748 789 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  790 + inviteStreamService.removeInviteInfo(inviteInfo);
749 791 };
750   - InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {
751   - logger.info("[录像下载]收到订阅消息: " + inviteStreamInfo.getCallId());
  792 + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> {
  793 + logger.info("[录像下载]收到订阅消息: " + jsonObject);
752 794 dynamicTask.stop(downLoadTimeOutTaskKey);
753   - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
754   - streamInfo.setStartTime(startTime);
755   - streamInfo.setEndTime(endTime);
756   - redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());
757   - downloadResult.setCode(ErrorCode.SUCCESS.getCode());
758   - downloadResult.setMsg(ErrorCode.SUCCESS.getMsg());
759   - downloadResult.setData(streamInfo);
760   - downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
761   - downloadResult.setResponse(inviteStreamInfo.getResponse());
762   - hookCallBack.call(downloadResult);
  795 + StreamInfo streamInfo = onPublishHandlerForDownload(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime);
  796 + if (streamInfo == null) {
  797 + logger.warn("[录像下载] 获取流地址信息失败");
  798 + callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
  799 + InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
  800 + return;
  801 + }
  802 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
  803 + logger.info("[录像下载] 调用成功 deviceId: {}, channelId: {}, 开始时间: {}, 结束时间: {}", device.getDeviceId(), channelId, startTime, endTime);
763 804 };
764 805 try {
765   - cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack,
766   - hookEvent, errorEvent, eventResult ->
767   - {
768   - if (eventResult.type == SipSubscribe.EventResultType.response) {
769   - ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
770   - String contentString = new String(responseEvent.getResponse().getRawContent());
771   - // 获取ssrc
772   - int ssrcIndex = contentString.indexOf("y=");
773   - // 检查是否有y字段
774   - if (ssrcIndex >= 0) {
775   - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
776   - String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
777   - // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
778   - if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
779   - return;
780   - }
781   - logger.info("[录像下载] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
782   - if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
783   - logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
784   -
785   - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
786   - // ssrc 不可用
  806 + cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed,
  807 + hookEvent, errorEvent, eventResult ->{
  808 + inviteInfo.setStatus(InviteSessionStatus.ok);
  809 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
  810 + String contentString = new String(responseEvent.getResponse().getRawContent());
  811 + // 获取ssrc
  812 + int ssrcIndex = contentString.indexOf("y=");
  813 + // 检查是否有y字段
  814 + if (ssrcIndex >= 0) {
  815 + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  816 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  817 + // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  818 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  819 + if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) {
  820 + String substring = contentString.substring(0, contentString.indexOf("y="));
  821 + try {
  822 + SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
  823 + int port = -1;
  824 + Vector mediaDescriptions = sdp.getMediaDescriptions(true);
  825 + for (Object description : mediaDescriptions) {
  826 + MediaDescription mediaDescription = (MediaDescription) description;
  827 + Media media = mediaDescription.getMedia();
  828 +
  829 + Vector mediaFormats = media.getMediaFormats(false);
  830 + if (mediaFormats.contains("96")) {
  831 + port = media.getMediaPort();
  832 + break;
  833 + }
  834 + }
  835 + logger.info("[录像下载-TCP主动连接对方] deviceId: {}, channelId: {}, 连接对方的地址:{}:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, sdp.getConnection().getAddress(), port, device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
  836 + JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServerItem, sdp.getConnection().getAddress(), port, ssrcInfo.getStream());
  837 + logger.info("[录像下载-TCP主动连接对方] 结果: {}", jsonObject);
  838 + } catch (SdpException e) {
  839 + logger.error("[录像下载-TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channelId, e);
  840 + dynamicTask.stop(downLoadTimeOutTaskKey);
  841 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
787 842 // 释放ssrc
788 843 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  844 +
789 845 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
790   - eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用";
791   - eventResult.statusCode = 400;
792   - errorEvent.response(eventResult);
793   - return;
  846 +
  847 + callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  848 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
  849 + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
  850 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(),
  851 + InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null);
794 852 }
  853 + }
  854 + return;
  855 + }
  856 + logger.info("[录像下载] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  857 + if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
  858 + logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  859 +
  860 + if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
  861 + // ssrc 不可用
  862 + // 释放ssrc
  863 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  864 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  865 + callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
  866 + InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
  867 + return;
  868 + }
  869 +
  870 + // 单端口模式streamId也有变化,需要重新设置监听
  871 + if (!mediaServerItem.isRtpEnable()) {
  872 + // 添加订阅
  873 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  874 + subscribe.removeSubscribe(hookSubscribe);
  875 + hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
  876 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
  877 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  878 + dynamicTask.stop(downLoadTimeOutTaskKey);
  879 + hookEvent.response(mediaServerItemInUse, response);
  880 + });
  881 + }
  882 +
  883 + // 更新ssrc
  884 + Boolean result = mediaServerService.updateRtpServerSSRC(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse);
  885 + if (!result) {
  886 + try {
  887 + logger.warn("[录像下载] 更新ssrc失败,停止录像回放 {}/{}", device.getDeviceId(), channelId);
  888 + cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
  889 + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
  890 + logger.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
795 891  
796   - // 单端口模式streamId也有变化,需要重新设置监听
797   - if (!mediaServerItem.isRtpEnable()) {
798   - // 添加订阅
799   - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
800   - subscribe.removeSubscribe(hookSubscribe);
801   - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
802   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
803   - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
804   - dynamicTask.stop(downLoadTimeOutTaskKey);
805   - // hook响应
806   - onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, hookCallBack);
807   - hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));
808   - });
809 892 }
810 893  
811   - // 关闭rtp server
812   - mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream(), result->{
813   - if (result) {
814   - // 重新开启ssrc server
815   - mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort(), true, device.getStreamModeForParam());
816   - }else {
817   - try {
818   - logger.warn("[录像下载] 停止{}/{}", device.getDeviceId(), channelId);
819   - cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null, null);
820   - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) {
821   - logger.error("[命令发送失败] 录像下载停止, 发送BYE: {}", e.getMessage());
822   - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
823   - }
  894 + dynamicTask.stop(downLoadTimeOutTaskKey);
  895 + // 释放ssrc
  896 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
824 897  
825   - dynamicTask.stop(downLoadTimeOutTaskKey);
826   - // 释放ssrc
827   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  898 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
828 899  
829   - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
830   - eventResult.msg = "下级自定义了ssrc,重新设置收流信息失败";
831   - eventResult.statusCode = 500;
832   - errorEvent.response(eventResult);
833   - }
834   - });
  900 + callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
  901 + "下级自定义了ssrc,重新设置收流信息失败", null);
  902 +
  903 + }else {
  904 + ssrcInfo.setSsrc(ssrcInResponse);
  905 + inviteInfo.setSsrcInfo(ssrcInfo);
  906 + inviteInfo.setStream(ssrcInfo.getStream());
835 907 }
  908 + }else {
  909 + logger.info("[录像下载] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
836 910 }
837 911 }
838 912 });
... ... @@ -849,21 +923,22 @@ public class PlayServiceImpl implements IPlayService {
849 923  
850 924 @Override
851 925 public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) {
852   - StreamInfo streamInfo = redisCatchStorage.queryDownload(deviceId, channelId, stream, null);
853   - if (streamInfo != null) {
854   - if (streamInfo.getProgress() == 1) {
855   - return streamInfo;
  926 + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream);
  927 +
  928 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
  929 + if (inviteInfo.getStreamInfo().getProgress() == 1) {
  930 + return inviteInfo.getStreamInfo();
856 931 }
857 932  
858 933 // 获取当前已下载时长
859   - String mediaServerId = streamInfo.getMediaServerId();
  934 + String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId();
860 935 MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
861 936 if (mediaServerItem == null) {
862 937 logger.warn("查询录像信息时发现节点已离线");
863 938 return null;
864 939 }
865 940 if (mediaServerItem.getRecordAssistPort() > 0) {
866   - JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, streamInfo.getApp(), streamInfo.getStream(), null);
  941 + JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream(), null);
867 942 if (jsonObject == null) {
868 943 throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接Assist服务失败");
869 944 }
... ... @@ -871,10 +946,10 @@ public class PlayServiceImpl implements IPlayService {
871 946 long duration = jsonObject.getLong("data");
872 947  
873 948 if (duration == 0) {
874   - streamInfo.setProgress(0);
  949 + inviteInfo.getStreamInfo().setProgress(0);
875 950 } else {
876   - String startTime = streamInfo.getStartTime();
877   - String endTime = streamInfo.getEndTime();
  951 + String startTime = inviteInfo.getStreamInfo().getStartTime();
  952 + String endTime = inviteInfo.getStreamInfo().getEndTime();
878 953 long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
879 954 long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
880 955  
... ... @@ -882,28 +957,29 @@ public class PlayServiceImpl implements IPlayService {
882 957 BigDecimal totalCount = new BigDecimal(end - start);
883 958 BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP);
884 959 double process = divide.doubleValue();
885   - streamInfo.setProgress(process);
  960 + inviteInfo.getStreamInfo().setProgress(process);
886 961 }
  962 + inviteStreamService.updateInviteInfo(inviteInfo);
887 963 }
888 964 }
  965 + return inviteInfo.getStreamInfo();
889 966 }
890   - return streamInfo;
  967 + return null;
891 968 }
892 969  
893   - private void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String uuid) {
894   - RequestMessage msg = new RequestMessage();
895   - msg.setKey(DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId);
896   - msg.setId(uuid);
897   - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
  970 + private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, JSONObject response, String deviceId, String channelId, String startTime, String endTime) {
  971 + StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, response, deviceId, channelId);
898 972 if (streamInfo != null) {
899   - redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());
900   - msg.setData(JSON.toJSONString(streamInfo));
901   - resultHolder.invokeResult(msg);
902   - } else {
903   - logger.warn("设备预览API调用失败!");
904   - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "设备预览API调用失败!"));
905   - resultHolder.invokeResult(msg);
  973 + streamInfo.setStartTime(startTime);
  974 + streamInfo.setEndTime(endTime);
  975 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.DOWNLOAD, deviceId, channelId);
  976 + if (inviteInfo != null) {
  977 + inviteInfo.setStatus(InviteSessionStatus.ok);
  978 + inviteInfo.setStreamInfo(streamInfo);
  979 + inviteStreamService.updateInviteInfo(inviteInfo);
  980 + }
906 981 }
  982 + return streamInfo;
907 983 }
908 984  
909 985  
... ... @@ -1007,15 +1083,14 @@ public class PlayServiceImpl implements IPlayService {
1007 1083  
1008 1084 @Override
1009 1085 public void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException {
1010   - String key = redisCatchStorage.queryPlaybackForKey(null, null, streamId, null);
1011   - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
1012   - if (null == streamInfo) {
  1086 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  1087 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
1013 1088 logger.warn("streamId不存在!");
1014 1089 throw new ServiceException("streamId不存在");
1015 1090 }
1016   - streamInfo.setPause(true);
1017   - redisTemplate.opsForValue().set(key, streamInfo);
1018   - MediaServerItem mediaServerItem = mediaServerService.getOne(streamInfo.getMediaServerId());
  1091 + inviteInfo.getStreamInfo().setPause(true);
  1092 + inviteStreamService.updateInviteInfo(inviteInfo);
  1093 + MediaServerItem mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
1019 1094 if (null == mediaServerItem) {
1020 1095 logger.warn("mediaServer 不存在!");
1021 1096 throw new ServiceException("mediaServer不存在");
... ... @@ -1025,21 +1100,20 @@ public class PlayServiceImpl implements IPlayService {
1025 1100 if (jsonObject == null || jsonObject.getInteger("code") != 0) {
1026 1101 throw new ServiceException("暂停RTP接收失败");
1027 1102 }
1028   - Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
1029   - cmder.playPauseCmd(device, streamInfo);
  1103 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
  1104 + cmder.playPauseCmd(device, inviteInfo.getStreamInfo());
1030 1105 }
1031 1106  
1032 1107 @Override
1033 1108 public void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException {
1034   - String key = redisCatchStorage.queryPlaybackForKey(null, null, streamId, null);
1035   - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
1036   - if (null == streamInfo) {
  1109 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  1110 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
1037 1111 logger.warn("streamId不存在!");
1038 1112 throw new ServiceException("streamId不存在");
1039 1113 }
1040   - streamInfo.setPause(false);
1041   - redisTemplate.opsForValue().set(key, streamInfo);
1042   - MediaServerItem mediaServerItem = mediaServerService.getOne(streamInfo.getMediaServerId());
  1114 + inviteInfo.getStreamInfo().setPause(false);
  1115 + inviteStreamService.updateInviteInfo(inviteInfo);
  1116 + MediaServerItem mediaServerItem = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
1043 1117 if (null == mediaServerItem) {
1044 1118 logger.warn("mediaServer 不存在!");
1045 1119 throw new ServiceException("mediaServer不存在");
... ... @@ -1049,7 +1123,7 @@ public class PlayServiceImpl implements IPlayService {
1049 1123 if (jsonObject == null || jsonObject.getInteger("code") != 0) {
1050 1124 throw new ServiceException("继续RTP接收失败");
1051 1125 }
1052   - Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
1053   - cmder.playResumeCmd(device, streamInfo);
  1126 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
  1127 + cmder.playResumeCmd(device, inviteInfo.getStreamInfo());
1054 1128 }
1055 1129 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
1 1 package com.genersoft.iot.vmp.storager;
2 2  
3 3 import com.alibaba.fastjson2.JSONObject;
4   -import com.genersoft.iot.vmp.common.StreamInfo;
5 4 import com.genersoft.iot.vmp.common.SystemAllInfo;
6   -import com.genersoft.iot.vmp.gb28181.bean.*;
7   -import com.genersoft.iot.vmp.media.zlm.dto.*;
  5 +import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage;
  6 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  7 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  8 +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  10 +import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
8 11 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
9 12 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
10 13 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
11   -import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
12 14 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
13 15  
14 16 import java.util.List;
... ... @@ -23,14 +25,6 @@ public interface IRedisCatchStorage {
23 25 */
24 26 Long getCSEQ();
25 27  
26   - boolean startPlayback(StreamInfo stream, String callId);
27   -
28   - boolean stopPlayback(String deviceId, String channelId, String stream, String callId);
29   -
30   - StreamInfo queryPlayback(String deviceId, String channelID, String stream, String callId);
31   -
32   - String queryPlaybackForKey(String deviceId, String channelId, String stream, String callId);
33   -
34 28 void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch);
35 29  
36 30 ParentPlatformCatch queryPlatformCatchInfo(String platformGbId);
... ... @@ -47,8 +41,6 @@ public interface IRedisCatchStorage {
47 41  
48 42 void delPlatformRegisterInfo(String callId);
49 43  
50   - void cleanPlatformRegisterInfos();
51   -
52 44 void updateSendRTPSever(SendRtpItem sendRtpItem);
53 45  
54 46 /**
... ... @@ -75,12 +67,6 @@ public interface IRedisCatchStorage {
75 67 boolean isChannelSendingRTP(String channelId);
76 68  
77 69 /**
78   - * 清空某个设备的所有缓存
79   - * @param deviceId 设备ID
80   - */
81   - void clearCatchByDeviceId(String deviceId);
82   -
83   - /**
84 70 * 在redis添加wvp的信息
85 71 */
86 72 void updateWVPInfo(JSONObject jsonObject, int time);
... ... @@ -120,23 +106,6 @@ public interface IRedisCatchStorage {
120 106 */
121 107 void removeStream(String mediaServerId, String type);
122 108  
123   - /**
124   - * 开始下载录像时存入
125   - * @param streamInfo
126   - */
127   - boolean startDownload(StreamInfo streamInfo, String callId);
128   -
129   - StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId);
130   -
131   - boolean stopDownload(String deviceId, String channelId, String stream, String callId);
132   -
133   - /**
134   - * 查找第三方系统留下的国标预设值
135   - * @param queryKey
136   - * @return
137   - */
138   - ThirdPartyGB queryMemberNoGBId(String queryKey);
139   -
140 109 List<OnStreamChangedHookParam> getStreams(String mediaServerId, String pull);
141 110  
142 111 /**
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
... ... @@ -2,17 +2,18 @@ package com.genersoft.iot.vmp.storager.impl;
2 2  
3 3 import com.alibaba.fastjson2.JSON;
4 4 import com.alibaba.fastjson2.JSONObject;
5   -import com.genersoft.iot.vmp.common.StreamInfo;
6 5 import com.genersoft.iot.vmp.common.SystemAllInfo;
7 6 import com.genersoft.iot.vmp.common.VideoManagerConstants;
8 7 import com.genersoft.iot.vmp.conf.UserSetting;
9   -import com.genersoft.iot.vmp.gb28181.bean.*;
10   -import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
  8 +import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage;
  9 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  10 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  11 +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
11 12 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 13 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
  14 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
13 15 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
14 16 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
15   -import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
16 17 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
17 18 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
18 19 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
... ... @@ -92,160 +93,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
92 93 }
93 94 }
94 95  
95   -
96   - @Override
97   - public boolean startPlayback(StreamInfo stream, String callId) {
98   - redisTemplate.opsForValue().set(String.format("%S_%s_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
99   - userSetting.getServerId(), stream.getMediaServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream);
100   - return true;
101   - }
102   -
103   - @Override
104   - public boolean startDownload(StreamInfo stream, String callId) {
105   - String key=String.format("%S_%s_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
106   - userSetting.getServerId(), stream.getMediaServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId);
107   - if (stream.getProgress() == 1) {
108   - logger.debug("添加下载缓存==已完成下载=》{}",key);
109   - redisTemplate.opsForValue().set(key, stream);
110   - }else {
111   - logger.debug("添加下载缓存==未完成下载=》{}",key);
112   - Duration duration = Duration.ofSeconds(60*60L);
113   - redisTemplate.opsForValue().set(key, stream, duration);
114   - }
115   - return true;
116   - }
117   - @Override
118   - public boolean stopDownload(String deviceId, String channelId, String stream, String callId) {
119   - DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
120   - if (deviceChannel != null) {
121   - deviceChannel.setStreamId(null);
122   - deviceChannel.setDeviceId(deviceId);
123   - deviceChannelMapper.update(deviceChannel);
124   - }
125   - if (deviceId == null) {
126   - deviceId = "*";
127   - }
128   - if (channelId == null) {
129   - channelId = "*";
130   - }
131   - if (stream == null) {
132   - stream = "*";
133   - }
134   - if (callId == null) {
135   - callId = "*";
136   - }
137   - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
138   - userSetting.getServerId(),
139   - deviceId,
140   - channelId,
141   - stream,
142   - callId
143   - );
144   - List<Object> scan = RedisUtil.scan(redisTemplate, key);
145   - if (scan.size() > 0) {
146   - for (Object keyObj : scan) {
147   - redisTemplate.delete(keyObj);
148   - }
149   - }
150   - return true;
151   - }
152   -
153   - @Override
154   - public boolean stopPlayback(String deviceId, String channelId, String stream, String callId) {
155   - DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
156   - if (deviceChannel != null) {
157   - deviceChannel.setStreamId(null);
158   - deviceChannel.setDeviceId(deviceId);
159   - deviceChannelMapper.update(deviceChannel);
160   - }
161   - if (deviceId == null) {
162   - deviceId = "*";
163   - }
164   - if (channelId == null) {
165   - channelId = "*";
166   - }
167   - if (stream == null) {
168   - stream = "*";
169   - }
170   - if (callId == null) {
171   - callId = "*";
172   - }
173   - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
174   - userSetting.getServerId(),
175   - deviceId,
176   - channelId,
177   - stream,
178   - callId
179   - );
180   - List<Object> scan = RedisUtil.scan(redisTemplate, key);
181   - if (scan.size() > 0) {
182   - for (Object keyObj : scan) {
183   - redisTemplate.delete(keyObj);
184   - }
185   - }
186   - return true;
187   - }
188   -
189   - @Override
190   - public StreamInfo queryPlayback(String deviceId, String channelId, String stream, String callId) {
191   - if (stream == null && callId == null) {
192   - return null;
193   - }
194   - if (deviceId == null) {
195   - deviceId = "*";
196   - }
197   - if (channelId == null) {
198   - channelId = "*";
199   - }
200   - if (stream == null) {
201   - stream = "*";
202   - }
203   - if (callId == null) {
204   - callId = "*";
205   - }
206   - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
207   - userSetting.getServerId(),
208   - deviceId,
209   - channelId,
210   - stream,
211   - callId
212   - );
213   - List<Object> streamInfoScan = RedisUtil.scan(redisTemplate, key);
214   - if (streamInfoScan.size() > 0) {
215   - return (StreamInfo) redisTemplate.opsForValue().get(streamInfoScan.get(0));
216   - }else {
217   - return null;
218   - }
219   - }
220   -
221   - @Override
222   - public String queryPlaybackForKey(String deviceId, String channelId, String stream, String callId) {
223   - if (stream == null && callId == null) {
224   - return null;
225   - }
226   - if (deviceId == null) {
227   - deviceId = "*";
228   - }
229   - if (channelId == null) {
230   - channelId = "*";
231   - }
232   - if (stream == null) {
233   - stream = "*";
234   - }
235   - if (callId == null) {
236   - callId = "*";
237   - }
238   - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
239   - userSetting.getServerId(),
240   - deviceId,
241   - channelId,
242   - stream,
243   - callId
244   - );
245   - List<Object> streamInfoScan = RedisUtil.scan(redisTemplate, key);
246   - return (String) streamInfoScan.get(0);
247   - }
248   -
249 96 @Override
250 97 public void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch) {
251 98 String key = VideoManagerConstants.PLATFORM_CATCH_PREFIX + userSetting.getServerId() + "_" + parentPlatformCatch.getId();
... ... @@ -292,14 +139,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
292 139 }
293 140  
294 141 @Override
295   - public void cleanPlatformRegisterInfos() {
296   - List regInfos = RedisUtil.scan(redisTemplate, VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetting.getServerId() + "_" + "*");
297   - for (Object key : regInfos) {
298   - redisTemplate.delete(key.toString());
299   - }
300   - }
301   -
302   - @Override
303 142 public void updateSendRTPSever(SendRtpItem sendRtpItem) {
304 143  
305 144 String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX +
... ... @@ -456,36 +295,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
456 295 }
457 296  
458 297 @Override
459   - public void clearCatchByDeviceId(String deviceId) {
460   - List<Object> playLeys = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_%s_*", VideoManagerConstants.PLAYER_PREFIX,
461   - userSetting.getServerId(),
462   - deviceId));
463   - if (playLeys.size() > 0) {
464   - for (Object key : playLeys) {
465   - redisTemplate.delete(key.toString());
466   - }
467   - }
468   -
469   - List<Object> playBackers = RedisUtil.scan(redisTemplate, String.format("%S_%s_*_%s_*_*_*", VideoManagerConstants.PLAY_BLACK_PREFIX,
470   - userSetting.getServerId(),
471   - deviceId));
472   - if (playBackers.size() > 0) {
473   - for (Object key : playBackers) {
474   - redisTemplate.delete(key.toString());
475   - }
476   - }
477   -
478   - List<Object> deviceCache = RedisUtil.scan(redisTemplate, String.format("%S%s_%s", VideoManagerConstants.DEVICE_PREFIX,
479   - userSetting.getServerId(),
480   - deviceId));
481   - if (deviceCache.size() > 0) {
482   - for (Object key : deviceCache) {
483   - redisTemplate.delete(key.toString());
484   - }
485   - }
486   - }
487   -
488   - @Override
489 298 public void updateWVPInfo(JSONObject jsonObject, int time) {
490 299 String key = VideoManagerConstants.WVP_SERVER_PREFIX + userSetting.getServerId();
491 300 Duration duration = Duration.ofSeconds(time);
... ... @@ -517,44 +326,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
517 326 }
518 327  
519 328 @Override
520   - public StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId) {
521   - if (stream == null && callId == null) {
522   - return null;
523   - }
524   - if (deviceId == null) {
525   - deviceId = "*";
526   - }
527   - if (channelId == null) {
528   - channelId = "*";
529   - }
530   - if (stream == null) {
531   - stream = "*";
532   - }
533   - if (callId == null) {
534   - callId = "*";
535   - }
536   - String key = String.format("%S_%s_*_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
537   - userSetting.getServerId(),
538   - deviceId,
539   - channelId,
540   - stream,
541   - callId
542   - );
543   - List<Object> streamInfoScan = RedisUtil.scan(redisTemplate, key);
544   - if (streamInfoScan.size() > 0) {
545   - return (StreamInfo) redisTemplate.opsForValue().get(streamInfoScan.get(0));
546   - }else {
547   - return null;
548   - }
549   - }
550   -
551   - @Override
552   - public ThirdPartyGB queryMemberNoGBId(String queryKey) {
553   - String key = VideoManagerConstants.WVP_STREAM_GB_ID_PREFIX + queryKey;
554   - return JsonUtil.redisJsonToObject(redisTemplate, key, ThirdPartyGB.class);
555   - }
556   -
557   - @Override
558 329 public void removeStream(String mediaServerId, String type) {
559 330 String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX + userSetting.getServerId() + "_" + type + "_*_*_" + mediaServerId;
560 331 List<Object> streams = RedisUtil.scan(redisTemplate, key);
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
... ... @@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
14 14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
15 15 import com.genersoft.iot.vmp.service.IDeviceChannelService;
16 16 import com.genersoft.iot.vmp.service.IDeviceService;
  17 +import com.genersoft.iot.vmp.service.IInviteStreamService;
17 18 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
18 19 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
19 20 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
... ... @@ -62,6 +63,9 @@ public class DeviceQuery {
62 63  
63 64 @Autowired
64 65 private IRedisCatchStorage redisCatchStorage;
  66 +
  67 + @Autowired
  68 + private IInviteStreamService inviteStreamService;
65 69  
66 70 @Autowired
67 71 private SIPCommander cmder;
... ... @@ -184,7 +188,7 @@ public class DeviceQuery {
184 188 // 清除redis记录
185 189 boolean isSuccess = deviceService.delete(deviceId);
186 190 if (isSuccess) {
187   - redisCatchStorage.clearCatchByDeviceId(deviceId);
  191 + inviteStreamService.clearInviteInfo(deviceId);
188 192 // 停止此设备的订阅更新
189 193 Set<String> allKeys = dynamicTask.getAllKeys();
190 194 for (String key : allKeys) {
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
1 1 package com.genersoft.iot.vmp.vmanager.gb28181.play;
2 2  
3   -import com.alibaba.fastjson2.JSON;
4 3 import com.alibaba.fastjson2.JSONArray;
5 4 import com.alibaba.fastjson2.JSONObject;
6 5 import com.genersoft.iot.vmp.common.InviteInfo;
... ... @@ -116,7 +115,7 @@ public class PlayController {
116 115 // 录像查询以channelId作为deviceId查询
117 116 resultHolder.put(key, uuid, result);
118 117  
119   - playService.play(newMediaServerItem, deviceId, channelId, ((code, msg, data) -> {
  118 + playService.play(newMediaServerItem, deviceId, channelId, (code, msg, data) -> {
120 119 WVPResult<StreamContent> wvpResult = new WVPResult<>();
121 120 if (code == InviteErrorCode.SUCCESS.getCode()) {
122 121 wvpResult.setCode(ErrorCode.SUCCESS.getCode());
... ... @@ -133,10 +132,9 @@ public class PlayController {
133 132 wvpResult.setCode(code);
134 133 wvpResult.setMsg(msg);
135 134 }
136   - System.out.println(JSON.toJSONString(wvpResult));
137 135 requestMessage.setData(wvpResult);
138 136 resultHolder.invokeResult(requestMessage);
139   - }));
  137 + });
140 138 return result;
141 139 }
142 140  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
1 1 package com.genersoft.iot.vmp.vmanager.gb28181.playback;
2 2  
  3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
3 5 import com.genersoft.iot.vmp.common.StreamInfo;
4 6 import com.genersoft.iot.vmp.conf.UserSetting;
5 7 import com.genersoft.iot.vmp.conf.exception.ControllerException;
6 8 import com.genersoft.iot.vmp.conf.exception.ServiceException;
7 9 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
  10 +import com.genersoft.iot.vmp.gb28181.bean.Device;
8 11 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
9 12 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  13 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
10 14 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
11   -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  15 +import com.genersoft.iot.vmp.service.IInviteStreamService;
12 16 import com.genersoft.iot.vmp.service.IPlayService;
  17 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
  18 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  19 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
13 20 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
14 21 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
15 22 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
... ... @@ -20,17 +27,13 @@ import org.slf4j.Logger;
20 27 import org.slf4j.LoggerFactory;
21 28 import org.springframework.beans.factory.annotation.Autowired;
22 29 import org.springframework.util.ObjectUtils;
23   -import org.springframework.web.bind.annotation.CrossOrigin;
24 30 import org.springframework.web.bind.annotation.GetMapping;
25 31 import org.springframework.web.bind.annotation.PathVariable;
26 32 import org.springframework.web.bind.annotation.RequestMapping;
27 33 import org.springframework.web.bind.annotation.RestController;
28   -
29   -import com.genersoft.iot.vmp.gb28181.bean.Device;
30   -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
31   -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
32 34 import org.springframework.web.context.request.async.DeferredResult;
33 35  
  36 +import javax.servlet.http.HttpServletRequest;
34 37 import javax.sip.InvalidArgumentException;
35 38 import javax.sip.SipException;
36 39 import java.text.ParseException;
... ... @@ -60,6 +63,9 @@ public class PlaybackController {
60 63 private IRedisCatchStorage redisCatchStorage;
61 64  
62 65 @Autowired
  66 + private IInviteStreamService inviteStreamService;
  67 +
  68 + @Autowired
63 69 private IPlayService playService;
64 70  
65 71 @Autowired
... ... @@ -74,8 +80,8 @@ public class PlaybackController {
74 80 @Parameter(name = "startTime", description = "开始时间", required = true)
75 81 @Parameter(name = "endTime", description = "结束时间", required = true)
76 82 @GetMapping("/start/{deviceId}/{channelId}")
77   - public DeferredResult<WVPResult<StreamContent>> start(@PathVariable String deviceId, @PathVariable String channelId,
78   - String startTime, String endTime) {
  83 + public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
  84 + String startTime, String endTime) {
79 85  
80 86 if (logger.isDebugEnabled()) {
81 87 logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
... ... @@ -86,22 +92,31 @@ public class PlaybackController {
86 92 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
87 93 resultHolder.put(key, uuid, result);
88 94  
89   - WVPResult<StreamContent> wvpResult = new WVPResult<>();
90   -
91   - RequestMessage msg = new RequestMessage();
92   - msg.setKey(key);
93   - msg.setId(uuid);
94   -
95   - playService.playBack(deviceId, channelId, startTime, endTime, null,
96   - playBackResult->{
97   - wvpResult.setCode(playBackResult.getCode());
98   - wvpResult.setMsg(playBackResult.getMsg());
99   - if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {
100   - StreamInfo streamInfo = (StreamInfo)playBackResult.getData();
101   - wvpResult.setData(new StreamContent(streamInfo));
  95 + RequestMessage requestMessage = new RequestMessage();
  96 + requestMessage.setKey(key);
  97 + requestMessage.setId(uuid);
  98 +
  99 + playService.playBack(deviceId, channelId, startTime, endTime,
  100 + (code, msg, data)->{
  101 +
  102 + WVPResult<StreamContent> wvpResult = new WVPResult<>();
  103 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  104 + wvpResult.setCode(ErrorCode.SUCCESS.getCode());
  105 + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
  106 +
  107 + if (data != null) {
  108 + StreamInfo streamInfo = (StreamInfo)data;
  109 + if (userSetting.getUseSourceIpAsStreamIp()) {
  110 + streamInfo.channgeStreamIp(request.getLocalName());
  111 + }
  112 + wvpResult.setData(new StreamContent(streamInfo));
  113 + }
  114 + }else {
  115 + wvpResult.setCode(code);
  116 + wvpResult.setMsg(msg);
102 117 }
103   - msg.setData(wvpResult);
104   - resultHolder.invokeResult(msg);
  118 + requestMessage.setData(wvpResult);
  119 + resultHolder.invokeResult(requestMessage);
105 120 });
106 121  
107 122 return result;
... ... @@ -169,14 +184,15 @@ public class PlaybackController {
169 184 @GetMapping("/seek/{streamId}/{seekTime}")
170 185 public void playSeek(@PathVariable String streamId, @PathVariable long seekTime) {
171 186 logger.info("playSeek: "+streamId+", "+seekTime);
172   - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
173   - if (null == streamInfo) {
  187 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  188 +
  189 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
174 190 logger.warn("streamId不存在!");
175 191 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
176 192 }
177   - Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
  193 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
178 194 try {
179   - cmder.playSeekCmd(device, streamInfo, seekTime);
  195 + cmder.playSeekCmd(device, inviteInfo.getStreamInfo(), seekTime);
180 196 } catch (InvalidArgumentException | ParseException | SipException e) {
181 197 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
182 198 }
... ... @@ -188,8 +204,9 @@ public class PlaybackController {
188 204 @GetMapping("/speed/{streamId}/{speed}")
189 205 public void playSpeed(@PathVariable String streamId, @PathVariable Double speed) {
190 206 logger.info("playSpeed: "+streamId+", "+speed);
191   - StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
192   - if (null == streamInfo) {
  207 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  208 +
  209 + if (null == inviteInfo || inviteInfo.getStreamInfo() == null) {
193 210 logger.warn("streamId不存在!");
194 211 throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
195 212 }
... ... @@ -197,9 +214,9 @@ public class PlaybackController {
197 214 logger.warn("不支持的speed: " + speed);
198 215 throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持的speed(0.25 0.5 1、2、4)");
199 216 }
200   - Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
  217 + Device device = storager.queryVideoDevice(inviteInfo.getDeviceId());
201 218 try {
202   - cmder.playSpeedCmd(device, streamInfo, speed);
  219 + cmder.playSpeedCmd(device, inviteInfo.getStreamInfo(), speed);
203 220 } catch (InvalidArgumentException | ParseException | SipException e) {
204 221 throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
205 222 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
1 1 package com.genersoft.iot.vmp.vmanager.gb28181.record;
2 2  
3 3 import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.conf.UserSetting;
4 5 import com.genersoft.iot.vmp.conf.exception.ControllerException;
5 6 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
6 7 import com.genersoft.iot.vmp.gb28181.bean.Device;
... ... @@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
10 11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
11 12 import com.genersoft.iot.vmp.service.IDeviceService;
12 13 import com.genersoft.iot.vmp.service.IPlayService;
  14 +import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
13 15 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
14 16 import com.genersoft.iot.vmp.utils.DateUtil;
15 17 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
... ... @@ -27,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
27 29 import org.springframework.web.bind.annotation.RestController;
28 30 import org.springframework.web.context.request.async.DeferredResult;
29 31  
  32 +import javax.servlet.http.HttpServletRequest;
30 33 import javax.sip.InvalidArgumentException;
31 34 import javax.sip.SipException;
32 35 import java.text.ParseException;
... ... @@ -55,8 +58,8 @@ public class GBRecordController {
55 58 @Autowired
56 59 private IDeviceService deviceService;
57 60  
58   -
59   -
  61 + @Autowired
  62 + private UserSetting userSetting;
60 63  
61 64 @Operation(summary = "录像查询")
62 65 @Parameter(name = "deviceId", description = "设备国标编号", required = true)
... ... @@ -119,8 +122,8 @@ public class GBRecordController {
119 122 @Parameter(name = "endTime", description = "结束时间", required = true)
120 123 @Parameter(name = "downloadSpeed", description = "下载倍速", required = true)
121 124 @GetMapping("/download/start/{deviceId}/{channelId}")
122   - public DeferredResult<WVPResult<StreamContent>> download(@PathVariable String deviceId, @PathVariable String channelId,
123   - String startTime, String endTime, String downloadSpeed) {
  125 + public DeferredResult<WVPResult<StreamContent>> download(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
  126 + String startTime, String endTime, String downloadSpeed) {
124 127  
125 128 if (logger.isDebugEnabled()) {
126 129 logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed));
... ... @@ -130,22 +133,32 @@ public class GBRecordController {
130 133 String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
131 134 DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(30000L);
132 135 resultHolder.put(key, uuid, result);
133   - RequestMessage msg = new RequestMessage();
134   - msg.setId(uuid);
135   - msg.setKey(key);
136   -
137   - WVPResult<StreamContent> wvpResult = new WVPResult<>();
138   -
139   - playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, playBackResult->{
140   -
141   - wvpResult.setCode(playBackResult.getCode());
142   - wvpResult.setMsg(playBackResult.getMsg());
143   - if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {
144   - StreamInfo streamInfo = (StreamInfo)playBackResult.getData();
145   - wvpResult.setData(new StreamContent(streamInfo));
  136 + RequestMessage requestMessage = new RequestMessage();
  137 + requestMessage.setId(uuid);
  138 + requestMessage.setKey(key);
  139 +
  140 +
  141 + playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed),
  142 + (code, msg, data)->{
  143 +
  144 + WVPResult<StreamContent> wvpResult = new WVPResult<>();
  145 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  146 + wvpResult.setCode(ErrorCode.SUCCESS.getCode());
  147 + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
  148 +
  149 + if (data != null) {
  150 + StreamInfo streamInfo = (StreamInfo)data;
  151 + if (userSetting.getUseSourceIpAsStreamIp()) {
  152 + streamInfo.channgeStreamIp(request.getLocalName());
  153 + }
  154 + wvpResult.setData(new StreamContent(streamInfo));
  155 + }
  156 + }else {
  157 + wvpResult.setCode(code);
  158 + wvpResult.setMsg(msg);
146 159 }
147   - msg.setData(wvpResult);
148   - resultHolder.invokeResult(msg);
  160 + requestMessage.setData(wvpResult);
  161 + resultHolder.invokeResult(requestMessage);
149 162 });
150 163  
151 164 return result;
... ...