Commit 1b72079593c937a78ef4c2370715f9dd2c40f9bc

Authored by xp.Huang
2 parents 71c6d651 a9f21c6b

Merge branch 'master_dev_gbt28181' into 'master_dev'

fix:云台控制传参参数错误

See merge request yunteng/thingskit!343
... ... @@ -12,6 +12,7 @@ import org.apache.curator.shaded.com.google.common.util.concurrent.Futures;
12 12 import org.apache.curator.shaded.com.google.common.util.concurrent.ListenableFuture;
13 13 import org.checkerframework.checker.nullness.qual.Nullable;
14 14 import org.jetbrains.annotations.NotNull;
  15 +import org.springframework.security.access.prepost.PreAuthorize;
15 16 import org.springframework.web.bind.annotation.*;
16 17 import org.springframework.web.context.request.async.DeferredResult;
17 18 import org.thingsboard.server.common.data.StringUtils;
... ... @@ -38,34 +39,67 @@ public class TkVideoControlController extends BaseController {
38 39
39 40 @GetMapping("/start/{deviceId}/{channelId}")
40 41 @ApiOperation(value = "视频点播/预览")
  42 + @PreAuthorize(
  43 + "@check.checkPermissions({'SYS_ADMIN','PLATFORM_ADMIN','TENANT_ADMIN','CUSTOMER_USER'},{'api:yt:video:control:play'})")
41 44 public DeferredResult<ResponseResult<StreamContentDTO>> startPlay(
42   - @PathVariable("deviceId") String tbDeviceId, @PathVariable("channelId") String channelId)
43   - throws ThingsboardException {
  45 + @PathVariable("deviceId") String tbDeviceId, @PathVariable("channelId") String channelId)
  46 + throws ThingsboardException {
44 47 if (StringUtils.isEmpty(tbDeviceId) || StringUtils.isEmpty(channelId)) {
45 48 throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
46 49 }
47 50 DeferredResult<ResponseResult<StreamContentDTO>> response = new DeferredResult<>();
48 51 ListenableFuture<StreamContentDTO> future =
49   - tkVideoControlService.startPlay(getCurrentUser(),tbDeviceId, channelId, getCurrentUser().getCurrentTenantId());
  52 + tkVideoControlService.startPlay(getCurrentUser(),tbDeviceId, channelId);
  53 + Futures.addCallback(
  54 + future,
  55 + new FutureCallback<>() {
  56 + @Override
  57 + public void onSuccess(@Nullable StreamContentDTO streamContentDTO) {
  58 + response.setResult(ResponseResult.success(streamContentDTO));
  59 + }
  60 +
  61 + @Override
  62 + public void onFailure(@NotNull Throwable throwable) {
  63 + response.setResult(ResponseResult.failed(throwable.getMessage()));
  64 + }
  65 + },
  66 + MoreExecutors.directExecutor());
  67 + return response;
  68 + }
  69 + @GetMapping("/sync/{deviceId}")
  70 + @ApiOperation(value = "摄像头通道同步")
  71 + @PreAuthorize(
  72 + "@check.checkPermissions({'SYS_ADMIN','PLATFORM_ADMIN','TENANT_ADMIN','CUSTOMER_USER'},{'api:yt:video:control:channel'})")
  73 + public DeferredResult<ResponseResult<String>> freshChannel(
  74 + @PathVariable("deviceId") String tbDeviceId)
  75 + throws ThingsboardException {
  76 + if (StringUtils.isEmpty(tbDeviceId) ) {
  77 + throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  78 + }
  79 + DeferredResult<ResponseResult<String>> response = new DeferredResult<>();
  80 + ListenableFuture<String> future =
  81 + tkVideoControlService.freshChannel(getCurrentUser(),tbDeviceId);
50 82 Futures.addCallback(
51   - future,
52   - new FutureCallback<>() {
53   - @Override
54   - public void onSuccess(@Nullable StreamContentDTO streamContentDTO) {
55   - response.setResult(ResponseResult.success(streamContentDTO));
56   - }
  83 + future,
  84 + new FutureCallback<>() {
  85 + @Override
  86 + public void onSuccess(@Nullable String result) {
  87 + response.setResult(ResponseResult.success(result));
  88 + }
57 89
58   - @Override
59   - public void onFailure(@NotNull Throwable throwable) {
60   - response.setResult(ResponseResult.failed(null));
61   - }
62   - },
63   - MoreExecutors.directExecutor());
  90 + @Override
  91 + public void onFailure(@NotNull Throwable throwable) {
  92 + response.setResult(ResponseResult.failed(throwable.getMessage()));
  93 + }
  94 + },
  95 + MoreExecutors.directExecutor());
64 96 return response;
65 97 }
66 98
67 99 @ApiOperation(value = "停止点播")
68 100 @GetMapping("/stop/{deviceId}/{channelId}")
  101 + @PreAuthorize(
  102 + "@check.checkPermissions({'SYS_ADMIN','PLATFORM_ADMIN','TENANT_ADMIN','CUSTOMER_USER'},{'api:yt:video:control:stop'})")
69 103 public ResponseResult playStop(
70 104 @ApiParam(value = "设备ID", required = true) @PathVariable("deviceId") String tbDeviceId,
71 105 @ApiParam(value = "通道ID", required = true) @PathVariable("channelId") String channelId)
... ... @@ -89,6 +123,8 @@ public class TkVideoControlController extends BaseController {
89 123 @Parameter(name = "verticalSpeed", description = "垂直速度", required = true)
90 124 @Parameter(name = "zoomSpeed", description = "缩放速度", required = true)
91 125 @GetMapping("/control/{tbDeviceId}/{channelId}")
  126 + @PreAuthorize(
  127 + "@check.checkPermissions({'SYS_ADMIN','PLATFORM_ADMIN','TENANT_ADMIN','CUSTOMER_USER'},{'api:yt:video:control:control'})")
92 128 public void ptzControl(
93 129 @PathVariable String tbDeviceId,
94 130 @PathVariable String channelId,
... ...
... ... @@ -17,11 +17,18 @@ public interface TkVideoControlService {
17 17 *
18 18 * @param deviceId 设备ID
19 19 * @param channelId 通道ID
20   - * @param tenantId 租户ID
21 20 * @return 视频流播放地址内容
22 21 */
23 22 ListenableFuture<StreamContentDTO> startPlay(
24   - SecurityUser currentUser, String deviceId, String channelId, String tenantId);
  23 + SecurityUser currentUser, String deviceId, String channelId);
  24 +
  25 + /**
  26 + * 摄像头通道同步
  27 + *
  28 + * @param deviceId 设备ID
  29 + * @return 视频流播放地址内容
  30 + */
  31 + ListenableFuture<String> freshChannel(SecurityUser currentUser, String deviceId);
25 32
26 33 /**
27 34 * 当点播时的推送处理程序
... ... @@ -41,20 +48,30 @@ public interface TkVideoControlService {
41 48 * @param channelId 通道ID
42 49 * @return 暂停播放结果 true成功 false失败
43 50 */
44   - boolean stopPlay(SecurityUser currentUser, String tbDeviceId, String channelId) throws ThingsboardException;
  51 + boolean stopPlay(SecurityUser currentUser, String tbDeviceId, String channelId)
  52 + throws ThingsboardException;
45 53
46 54 /**
47 55 * 摄像头控制
  56 + *
48 57 * @param currentUser 登录用户
49 58 * @param tbDeviceId 设备ID
50 59 * @param channelId 设备通道
51   - * @param command 控制指令
  60 + * @param command 控制指令
52 61 * @param horizonSpeed 水平速度
53 62 * @param verticalSpeed 垂直速度
54 63 * @param zoomSpeed 缩放速度
55 64 * @return
56 65 */
57   - boolean control(SecurityUser currentUser, String tbDeviceId, String channelId, PTZCommandEnum command, int horizonSpeed, int verticalSpeed, int zoomSpeed) throws ThingsboardException;
  66 + boolean control(
  67 + SecurityUser currentUser,
  68 + String tbDeviceId,
  69 + String channelId,
  70 + PTZCommandEnum command,
  71 + int horizonSpeed,
  72 + int verticalSpeed,
  73 + int zoomSpeed)
  74 + throws ThingsboardException;
58 75
59 76 StreamInfoDTO play(
60 77 SecurityUser currentUser,
... ... @@ -63,11 +80,14 @@ public interface TkVideoControlService {
63 80 SsrcInfoDTO ssrcInfo,
64 81 SipDeviceDTO device,
65 82 String channelId);
  83 +
66 84 public void byeCmdInSsrcTransaction(
67   - String tenantId,
68   - boolean oneWay,
69   - String tbDeviceId,
70   - String cameraCode,String channelId,String streamId,
71   - Consumer<FromDeviceRpcResponse> responseConsumer)
72   - throws ThingsboardException;
  85 + String tenantId,
  86 + boolean oneWay,
  87 + String tbDeviceId,
  88 + String cameraCode,
  89 + String channelId,
  90 + String streamId,
  91 + Consumer<FromDeviceRpcResponse> responseConsumer)
  92 + throws ThingsboardException;
73 93 }
... ...
... ... @@ -31,9 +31,7 @@ import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
31 31 import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO;
32 32 import org.thingsboard.server.common.data.yunteng.dto.sip.*;
33 33 import org.thingsboard.server.common.data.yunteng.dto.sip.hook.param.HookSubscribeForStreamChange;
34   -import org.thingsboard.server.common.data.yunteng.enums.PTZCommandEnum;
35   -import org.thingsboard.server.common.data.yunteng.enums.SessionTypeEnum;
36   -import org.thingsboard.server.common.data.yunteng.enums.VideoMethodEnum;
  34 +import org.thingsboard.server.common.data.yunteng.enums.*;
37 35 import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil;
38 36 import org.thingsboard.server.common.data.yunteng.utils.ZLMediaKitRestFulUtils;
39 37 import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
... ... @@ -63,7 +61,8 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
63 61
64 62 @Override
65 63 public ListenableFuture<StreamContentDTO> startPlay(
66   - SecurityUser currentUser, String deviceId, String channelId, String tenantId) {
  64 + SecurityUser currentUser, String deviceId, String channelId) {
  65 + String tenantId = currentUser.getCurrentTenantId();
67 66 // 判断设备、通道是否存在
68 67 DeviceDTO deviceDTO = tkDeviceService.checkDeviceByTenantIdAndId(tenantId, deviceId, true);
69 68 SipDeviceDTO sipDeviceDTO =
... ... @@ -74,7 +73,9 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
74 73 if (null == sipDeviceDTO) {
75 74 throw new TkDataValidationException(ErrorMessage.FOUND_VIDEO_DEVICE_FAILED.getMessage());
76 75 }
77   - VideoChanelDTO videoChanelDTO = tkVideoChannelService.findVideoChannelById(sipDeviceDTO.getCameraCode(), channelId, tenantId);
  76 + VideoChanelDTO videoChanelDTO =
  77 + tkVideoChannelService.findVideoChannelById(
  78 + sipDeviceDTO.getCameraCode(), channelId, tenantId);
78 79 if (null == videoChanelDTO) {
79 80 throw new TkDataValidationException(ErrorMessage.VIDEO_CHANNEL_NOT_FOUND.getMessage());
80 81 }
... ... @@ -114,6 +115,69 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
114 115 }
115 116
116 117 @Override
  118 + public ListenableFuture<String> freshChannel(SecurityUser currentUser, String deviceId) {
  119 + String tenantId = currentUser.getCurrentTenantId();
  120 + // 判断设备、通道是否存在
  121 + Optional<DeviceDTO> device = Optional.ofNullable(tkDeviceService.checkDeviceByTenantIdAndId(tenantId, deviceId, true));
  122 + if(device.isEmpty()){
  123 + return Futures.immediateFuture(ErrorMessage.DEVICE_NOT_EXTIED.getMessage());
  124 + }
  125 + DeviceDTO deviceDTO = device.get();
  126 + if (!deviceDTO.getDeviceState().equals(DeviceState.ONLINE)) {
  127 + return Futures.immediateFuture(ErrorMessage.DEVICE_NOT_ONLINE.getMessage());
  128 + }
  129 + SipDeviceDTO sipDeviceDTO =
  130 + JacksonUtil.convertValue(
  131 + deviceDTO.getDeviceInfo().get(FastIotConstants.DeviceAdditional.SIP),
  132 + SipDeviceDTO.class);
  133 + // 获取设备的附加信息
  134 + if (null == sipDeviceDTO) {
  135 + throw new TkDataValidationException(ErrorMessage.FOUND_VIDEO_DEVICE_FAILED.getMessage());
  136 + }
  137 + CountDownLatch timeoutLatch = new CountDownLatch(1);
  138 + AtomicReference<String> result = new AtomicReference<>();
  139 + // 进行命令发送
  140 +
  141 +
  142 + ObjectNode paramJson = JacksonUtil.newObjectNode();
  143 + paramJson.put(FastIotConstants.ZLMediaBody.MSG_TYPE, VideoXmlEnum.Query.name());
  144 + int sn = (int) ((Math.random() * 9 + 1) * 100000);
  145 + paramJson.put(FastIotConstants.ZLMediaBody.MSG_CONTEXT, sn);
  146 +
  147 + try {
  148 + cameraCommonCmd(
  149 + currentUser.getCurrentTenantId(),
  150 + paramJson,
  151 + sipDeviceDTO.getCameraCode(),
  152 + VideoMethodEnum.MESSAGE,
  153 + false,
  154 + deviceId,
  155 + fromDeviceRpcResponse -> {
  156 + log.warn(
  157 + "【流媒体SIP】收到【视频点播】结果=异常【{}】+数据【{}】",
  158 + fromDeviceRpcResponse.getError(),
  159 + fromDeviceRpcResponse.getResponse());
  160 + fromDeviceRpcResponse
  161 + .getResponse()
  162 + .ifPresent(
  163 + jsonStr -> {
  164 + JsonNode responseJson = JacksonUtil.toJsonNode(jsonStr);
  165 + if (fromDeviceRpcResponse.getError().isEmpty()) {
  166 + result.set(jsonStr);
  167 + } else {
  168 + result.set(fromDeviceRpcResponse.getError().get().name());
  169 + }
  170 + });
  171 + timeoutLatch.countDown();
  172 + });
  173 + } catch (ThingsboardException e) {
  174 + Futures.immediateFailedFuture(e);
  175 + }
  176 + return Futures.immediateFuture(result.get());
  177 +
  178 + }
  179 +
  180 + @Override
117 181 public StreamInfoDTO onPublishHandlerForPlay(
118 182 MediaServerDTO mediaServerItem, JsonNode response, String deviceCode, String channelId) {
119 183 StreamInfoDTO streamInfo = onPublishHandler(mediaServerItem, response, deviceCode, channelId);
... ... @@ -130,37 +194,41 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
130 194 }
131 195
132 196 @Override
133   - public boolean stopPlay(SecurityUser currentUser, String tbDeviceId, String channelId) throws ThingsboardException {
134   - String tenantId = currentUser.getCurrentTenantId();
135   - DeviceDTO deviceDTO = tkDeviceService.findDeviceInfoByTbDeviceId(tenantId, tbDeviceId);
136   - if (null == deviceDTO
137   - || !deviceDTO.getDeviceInfo().has(FastIotConstants.DeviceAdditional.SIP)) {
138   - throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
139   - }
140   - String cameraCode =
141   - deviceDTO
142   - .getDeviceInfo()
143   - .get(FastIotConstants.DeviceAdditional.SIP)
144   - .get(FastIotConstants.ZLMediaBody.CAMERA_CODE)
145   - .asText();
146   -
147   - Optional<StreamInfoDTO> streamInfoDTO =
148   - tkCacheStorageService.queryPlayStreamByChannel(cameraCode, channelId);
149   - if (streamInfoDTO.isEmpty()) {
150   - throw new TkDataValidationException(
151   - ErrorMessage.STREAM_INFO_NOT_FOUND_FOR_PLAY.getMessage());
152   - }
153   - byeCmdInSsrcTransaction(
154   - currentUser.getCurrentTenantId(),
155   - false,
156   - tbDeviceId,
157   - cameraCode,channelId,streamInfoDTO.get().getStream(),
158   - fromDeviceRpcResponse->{
159   -
160   - });
  197 + public boolean stopPlay(SecurityUser currentUser, String tbDeviceId, String channelId)
  198 + throws ThingsboardException {
  199 + String tenantId = currentUser.getCurrentTenantId();
  200 + DeviceDTO deviceDTO = tkDeviceService.findDeviceInfoByTbDeviceId(tenantId, tbDeviceId);
  201 + if (null == deviceDTO
  202 + || !deviceDTO.getDeviceInfo().has(FastIotConstants.DeviceAdditional.SIP)) {
  203 + throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  204 + }
  205 + String cameraCode =
  206 + deviceDTO
  207 + .getDeviceInfo()
  208 + .get(FastIotConstants.DeviceAdditional.SIP)
  209 + .get(FastIotConstants.ZLMediaBody.CAMERA_CODE)
  210 + .asText();
  211 +
  212 + Optional<StreamInfoDTO> streamInfoDTO =
  213 + tkCacheStorageService.queryPlayStreamByChannel(cameraCode, channelId);
  214 + if (streamInfoDTO.isEmpty()) {
  215 + throw new TkDataValidationException(ErrorMessage.STREAM_INFO_NOT_FOUND_FOR_PLAY.getMessage());
  216 + }
  217 + byeCmdInSsrcTransaction(
  218 + currentUser.getCurrentTenantId(),
  219 + false,
  220 + tbDeviceId,
  221 + cameraCode,
  222 + channelId,
  223 + streamInfoDTO.get().getStream(),
  224 + fromDeviceRpcResponse -> {});
161 225
162   - tkCacheStorageService.deleteCacheStreamInfoByStopPlay(streamInfoDTO.get()); //redisCatchStorage.stopPlay(streamInfo);
163   - return tkVideoChannelService.updateVideoChannelStreamId(null, cameraCode, channelId);//storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
  226 + tkCacheStorageService.deleteCacheStreamInfoByStopPlay(
  227 + streamInfoDTO.get()); // redisCatchStorage.stopPlay(streamInfo);
  228 + return tkVideoChannelService.updateVideoChannelStreamId(
  229 + null,
  230 + cameraCode,
  231 + channelId); // storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
164 232 }
165 233
166 234 @Override
... ... @@ -214,7 +282,8 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
214 282 mediaServerDTO.getMediaServerId(), ssrcInfoDTO.getSsrc());
215 283 videoStreamSessionManager.remove(
216 284 sipDeviceDTO.getCameraCode(), channelId, ssrcInfoDTO.getStream());
217   - throw new TkDataValidationException(ErrorMessage.GET_PLAY_PORT_FAILED.getMessage());
  285 + throw new TkDataValidationException(
  286 + String.format(ErrorMessage.GET_PLAY_PORT_FAILED.getMessage(), mediaServerDTO.getIp()));
218 287 }
219 288 // 进行命令发送
220 289 AtomicReference<StreamInfoDTO> result = new AtomicReference<>();
... ... @@ -263,9 +332,12 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
263 332 sipDeviceDTO.getCameraCode(),
264 333 VideoMethodEnum.INVITE,
265 334 false,
266   - tbDeviceId,
  335 + tbDeviceId,
267 336 fromDeviceRpcResponse -> {
268   - log.warn("【流媒体SIP】收到【视频点播】结果=异常【{}】+数据【{}】",fromDeviceRpcResponse.getError(), fromDeviceRpcResponse.getResponse());
  337 + log.warn(
  338 + "【流媒体SIP】收到【视频点播】结果=异常【{}】+数据【{}】",
  339 + fromDeviceRpcResponse.getError(),
  340 + fromDeviceRpcResponse.getResponse());
269 341 fromDeviceRpcResponse
270 342 .getResponse()
271 343 .ifPresent(
... ... @@ -298,7 +370,7 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
298 370 } catch (Exception e) {
299 371 zlMediaKitTaskUtils.stop(timeOutTaskKey);
300 372 tkMediaServerNodeService.closeRTPServer(
301   - Optional.ofNullable(mediaServerDTO), ssrcInfoDTO.getStream());
  373 + Optional.of(mediaServerDTO), ssrcInfoDTO.getStream());
302 374 // 释放ssrc
303 375 tkMediaServerNodeService.releaseSsrc(mediaServerDTO.getId(), ssrcInfoDTO.getSsrc());
304 376
... ... @@ -466,8 +538,15 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
466 538 boolean persisted = false;
467 539 ToDeviceRpcRequest rpcRequest =
468 540 new ToDeviceRpcRequest(
469   - rpcRequestUUID, new TenantId(UUID.fromString(tenantId)),
470   - new DeviceId(UUID.fromString(deviceId)), oneWay, expTime, body, persisted, null, null);
  541 + rpcRequestUUID,
  542 + new TenantId(UUID.fromString(tenantId)),
  543 + new DeviceId(UUID.fromString(deviceId)),
  544 + oneWay,
  545 + expTime,
  546 + body,
  547 + persisted,
  548 + null,
  549 + null);
471 550 deviceRpcService.processRestApiRpcRequest(rpcRequest, responseConsumer, null);
472 551 } catch (IllegalArgumentException ioe) {
473 552 throw new ThingsboardException(
... ... @@ -485,69 +564,90 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
485 564 */
486 565 @Override
487 566 public void byeCmdInSsrcTransaction(
488   - String tenantId,
489   - boolean oneWay,
490   - String tbDeviceId,
491   - String cameraCode,String channelId,String streamId,
492   - Consumer<FromDeviceRpcResponse> responseConsumer)
493   - throws ThingsboardException {
494   - Optional<SsrcTransactionDTO> transactionDTO = videoStreamSessionManager.getSsrcTransaction(cameraCode,channelId,streamId);
  567 + String tenantId,
  568 + boolean oneWay,
  569 + String tbDeviceId,
  570 + String cameraCode,
  571 + String channelId,
  572 + String streamId,
  573 + Consumer<FromDeviceRpcResponse> responseConsumer)
  574 + throws ThingsboardException {
  575 + Optional<SsrcTransactionDTO> transactionDTO =
  576 + videoStreamSessionManager.getSsrcTransaction(cameraCode, channelId, streamId);
495 577 if (transactionDTO.isEmpty()) {
496   - throw new TkDataValidationException(
497   - ErrorMessage.STREAM_INFO_NOT_FOUND_FOR_PLAY.getMessage());
  578 + throw new TkDataValidationException(ErrorMessage.STREAM_INFO_NOT_FOUND_FOR_PLAY.getMessage());
498 579 }
499 580 SsrcTransactionDTO ssrc = transactionDTO.get();
500 581 cameraByeCmd(
501   - tenantId,ssrc.getSipTransactionInfo(),oneWay,true,tbDeviceId,
502   - cameraCode,channelId,streamId,ssrc.getSsrc(),ssrc.getMediaServerId(),
503   - responseConsumer);
  582 + tenantId,
  583 + ssrc.getSipTransactionInfo(),
  584 + oneWay,
  585 + true,
  586 + tbDeviceId,
  587 + cameraCode,
  588 + channelId,
  589 + streamId,
  590 + ssrc.getSsrc(),
  591 + ssrc.getMediaServerId(),
  592 + responseConsumer);
504 593 }
505 594
506 595 public void byeCmdInSendRtp(
507   - SecurityUser currentUser,
508   - boolean oneWay,
509   - String tbDeviceId,
510   - String cameraCode,String channelId,String streamId,
511   - Consumer<FromDeviceRpcResponse> responseConsumer)
512   - throws ThingsboardException {
513   -
514   -// SendRtpItemDTO sendRtpItem =null;
515   -// SipMessageHeaderDTO sipTransactionInfo =
516   -// SipMessageHeaderDTO.builder()
517   -// .toTag(sendRtpItem.getToTag())
518   -// .fromTag(sendRtpItem.getFromTag())
519   -// .callId(sendRtpItem.getCallId())
520   -// .build();
521   -// MediaServerDTO mediaServer = tkMediaServerService.getMediaServerByMediaServerId(sendRtpItem.getMediaServerId());
522   -// cameraByeCmd(
523   -// currentUser,ssrc.getSipTransactionInfo(),oneWay,mediaServer != null,tbDeviceId,
524   -// cameraCode,sendRtpItem.getChannelId(),streamId,ssrc.getSsrc(),ssrc.getMediaServerId(),
525   -// responseConsumer);
526   - }
  596 + SecurityUser currentUser,
  597 + boolean oneWay,
  598 + String tbDeviceId,
  599 + String cameraCode,
  600 + String channelId,
  601 + String streamId,
  602 + Consumer<FromDeviceRpcResponse> responseConsumer)
  603 + throws ThingsboardException {
527 604
  605 + // SendRtpItemDTO sendRtpItem =null;
  606 + // SipMessageHeaderDTO sipTransactionInfo =
  607 + // SipMessageHeaderDTO.builder()
  608 + // .toTag(sendRtpItem.getToTag())
  609 + // .fromTag(sendRtpItem.getFromTag())
  610 + // .callId(sendRtpItem.getCallId())
  611 + // .build();
  612 + // MediaServerDTO mediaServer =
  613 + // tkMediaServerService.getMediaServerByMediaServerId(sendRtpItem.getMediaServerId());
  614 + // cameraByeCmd(
  615 + // currentUser,ssrc.getSipTransactionInfo(),oneWay,mediaServer != null,tbDeviceId,
  616 + //
  617 + // cameraCode,sendRtpItem.getChannelId(),streamId,ssrc.getSsrc(),ssrc.getMediaServerId(),
  618 + // responseConsumer);
  619 + }
528 620
529 621 public void cameraByeCmd(
530   - String currentUser,SipMessageHeaderDTO messageHeaderDTO,
531   - boolean oneWay,boolean mediaOnline,
532   - String tbDeviceId,
533   - String cameraCode,String channelId,String streamId,String ssrc,String mediaServerId,
534   - Consumer<FromDeviceRpcResponse> responseConsumer) throws ThingsboardException {
535   - if(mediaOnline){
536   - tkMediaServerNodeService.releaseSsrc(mediaServerId,ssrc);
537   - tkMediaServerNodeService.closeRTPServer(mediaServerId,streamId);
  622 + String currentUser,
  623 + SipMessageHeaderDTO messageHeaderDTO,
  624 + boolean oneWay,
  625 + boolean mediaOnline,
  626 + String tbDeviceId,
  627 + String cameraCode,
  628 + String channelId,
  629 + String streamId,
  630 + String ssrc,
  631 + String mediaServerId,
  632 + Consumer<FromDeviceRpcResponse> responseConsumer)
  633 + throws ThingsboardException {
  634 + if (mediaOnline) {
  635 + tkMediaServerNodeService.releaseSsrc(mediaServerId, ssrc);
  636 + tkMediaServerNodeService.closeRTPServer(mediaServerId, streamId);
538 637 }
539   - videoStreamSessionManager.remove(cameraCode,channelId,streamId);
  638 + videoStreamSessionManager.remove(cameraCode, channelId, streamId);
540 639 ObjectNode paramJson = JacksonUtil.newObjectNode();
541 640 paramJson.put(FastIotConstants.ZLMediaBody.CHANNEL_ID, channelId);
542   - paramJson.set(FastIotConstants.ZLMediaBody.MSG_HEADER, JacksonUtil.valueToTree(messageHeaderDTO));
  641 + paramJson.set(
  642 + FastIotConstants.ZLMediaBody.MSG_HEADER, JacksonUtil.valueToTree(messageHeaderDTO));
543 643 cameraCommonCmd(
544   - currentUser,
545   - paramJson,
546   - cameraCode,
547   - VideoMethodEnum.BYE,
548   - oneWay,
549   - tbDeviceId,
550   - responseConsumer);
  644 + currentUser,
  645 + paramJson,
  646 + cameraCode,
  647 + VideoMethodEnum.BYE,
  648 + oneWay,
  649 + tbDeviceId,
  650 + responseConsumer);
551 651 }
552 652
553 653 /**
... ... @@ -687,11 +787,11 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
687 787 byeCmdInSsrcTransaction(
688 788 currentUser.getCurrentTenantId(),
689 789 false,
690   - tbDeviceId,
691   - cameraCode,channelId,streamId,
692   - fromDeviceRpcResponse->{
693   -
694   - });
  790 + tbDeviceId,
  791 + cameraCode,
  792 + channelId,
  793 + streamId,
  794 + fromDeviceRpcResponse -> {});
695 795 } catch (Exception e) {
696 796 log.error("[命令发送失败] 停止点播, 发送BYE: {}", e.getMessage());
697 797 }
... ... @@ -707,21 +807,31 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
707 807 }
708 808
709 809 @Override
710   - public boolean control(SecurityUser currentUser, String tbDeviceId, String channelId, PTZCommandEnum command, int horizonSpeed, int verticalSpeed, int zoomSpeed) throws ThingsboardException {
  810 + public boolean control(
  811 + SecurityUser currentUser,
  812 + String tbDeviceId,
  813 + String channelId,
  814 + PTZCommandEnum command,
  815 + int horizonSpeed,
  816 + int verticalSpeed,
  817 + int zoomSpeed)
  818 + throws ThingsboardException {
711 819
712 820 if (PTZCommandEnum.STOP.equals(command)) {
713 821 horizonSpeed = 0;
714 822 verticalSpeed = 0;
715 823 zoomSpeed = 0;
716 824 }
717   - DeviceDTO deviceDTO = tkDeviceService.checkDeviceByTenantIdAndId(currentUser.getCurrentTenantId(), tbDeviceId, true);
  825 + DeviceDTO deviceDTO =
  826 + tkDeviceService.checkDeviceByTenantIdAndId(
  827 + currentUser.getCurrentTenantId(), tbDeviceId, true);
718 828 if (null == deviceDTO) {
719 829 throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
720 830 }
721 831 SipDeviceDTO sipDeviceDTO =
722   - JacksonUtil.convertValue(
723   - deviceDTO.getDeviceInfo().get(FastIotConstants.DeviceAdditional.SIP),
724   - SipDeviceDTO.class);
  832 + JacksonUtil.convertValue(
  833 + deviceDTO.getDeviceInfo().get(FastIotConstants.DeviceAdditional.SIP),
  834 + SipDeviceDTO.class);
725 835 if (null == sipDeviceDTO) {
726 836 throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
727 837 }
... ... @@ -732,17 +842,17 @@ public class TkVideoControlServiceImpl implements TkVideoControlService {
732 842 ptzCmdDTO.setZoomSpeed(zoomSpeed);
733 843 ObjectNode requestJson = JacksonUtil.newObjectNode();
734 844 requestJson.put(FastIotConstants.ZLMediaBody.CHANNEL_ID, channelId);
735   - requestJson.set(FastIotConstants.ZLMediaBody.CONTROL_CONTEXT, JacksonUtil.valueToTree(ptzCmdDTO));
  845 + requestJson.put(FastIotConstants.ZLMediaBody.MSG_TYPE, VideoXmlEnum.Control.name());
  846 + requestJson.set(
  847 + FastIotConstants.ZLMediaBody.MSG_CONTEXT, JacksonUtil.valueToTree(ptzCmdDTO));
736 848 cameraCommonCmd(
737   - currentUser.getCurrentTenantId(),
738   - requestJson,
739   - sipDeviceDTO.getCameraCode(),
740   - VideoMethodEnum.MESSAGE,
741   - false,
742   - tbDeviceId,
743   - fromDeviceRpcResponse->{
744   -
745   - });
  849 + currentUser.getCurrentTenantId(),
  850 + requestJson,
  851 + sipDeviceDTO.getCameraCode(),
  852 + VideoMethodEnum.MESSAGE,
  853 + false,
  854 + tbDeviceId,
  855 + fromDeviceRpcResponse -> {});
746 856 return false;
747 857 }
748 858 }
... ...
... ... @@ -1203,10 +1203,10 @@ file:
1203 1203 type: ${FILE_STORAGE_TYPE:minio} #minio, or other to be implemented
1204 1204 randomFileName: ${FILE_STORAGE_FILENAME:true} #是否重命名文件名字,防止冲突
1205 1205 minio:
1206   - minioUrl: ${MINIO_URL:https://demo.thingskit.com:9000} #minio储存地址
1207   - minioName: ${MINIO_NAME:thingskit} #minio账户
1208   - minioPass: ${MINIO_PWD:Dzr227+bjsz} #minio访问密码
1209   - bucketName: yunteng-test #minio储存桶名称
  1206 + minioUrl: ${MINIO_URL:http://127.0.0.1:9000} #minio储存地址
  1207 + minioName: ${MINIO_NAME:xxxxxx} #minio账户
  1208 + minioPass: ${MINIO_PWD:xxxxx} #minio访问密码
  1209 + bucketName: ${MINIO_BUCKET_NAME:yunteng-test} #minio储存桶名称
1210 1210 randomFileName: ${file.storage.randomFileName}
1211 1211 account:
1212 1212 info:
... ... @@ -1246,13 +1246,13 @@ sip:
1246 1246 password: ${GBT28181_SIP_PASSWORD:61332286}
1247 1247 #zlm 默认服务器配置
1248 1248 media:
1249   - id: ${GBT28181_MEDIA_GENERAL_ID:f6GfbO0BGEaROKLP}
  1249 + id: ${GBT28181_MEDIA_GENERAL_ID:D2okJWKKaQ5bX7Va}
1250 1250 # [必须修改] zlm服务器的内网IP
1251   - ip: ${GBT28181_MEDIA_IP:192.168.1.16}
  1251 + ip: ${GBT28181_MEDIA_IP:192.168.1.20}
1252 1252 # [必须修改] zlm服务器的http.port
1253 1253 http-port: ${GBT28181_MEDIA_HTTP_PORT:28080}
1254 1254 # [可选] zlm服务器的hook.admin_params=secret
1255   - secret: ${GBT28181_MEDIA_API_SECRET:5PnbPDCcxQGeK15OowHPPdSgort2Cx9Y}
  1255 + secret: ${GBT28181_MEDIA_API_SECRET:QhrTN7k6HcDnt0YyeolwHwiVYDgIHPMZ}
1256 1256 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
1257 1257 rtp:
1258 1258 # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
... ...
... ... @@ -184,8 +184,8 @@ public interface FastIotConstants {
184 184 /** 请求响应事件:表单内容 */
185 185 String MSG_CONTEXT = "msgContext";
186 186
187   - /** 设备控制内容 */
188   - String CONTROL_CONTEXT = "ptzContext";
  187 + /** 消息类型,例如:查询、控制等 */
  188 + String MSG_TYPE = "xmlRoot";
189 189
190 190 /** 订阅处理结果 */
191 191 String SESSION_TYPE = "sessionType";
... ... @@ -206,6 +206,7 @@ public interface FastIotConstants {
206 206 String UDP = "UDP";
207 207 }
208 208
  209 +
209 210 interface TBCacheConfig {
210 211 String TB_CACHE_CONFIG_KEY = "TB_CONNECT_CACHE";
211 212 String EXISTING_TENANT = "EXISTING_TENANT";
... ...
... ... @@ -123,16 +123,18 @@ public enum ErrorMessage {
123 123 SSRC_INFO_NOT_FOUND(400098,"缓存事务信息未找到,设备【%s】 通道【%s】"),
124 124 VIDEO_CHANNEL_NOT_FOUND(400099,"视频通道不存在"),
125 125 ONLINE_MEDIA_SERVER_NOT_FOUND(400100,"没有可用的流媒体节点"),
126   - FOUND_VIDEO_DEVICE_FAILED(400101,"获取视频设备信息失败"),
  126 + FOUND_VIDEO_DEVICE_FAILED(400101,"视频设备SIP信息丢失"),
127 127 NOT_FOUND_MEDIA_SERVER_FOR_PLAY(400102,"未找到可用于播放的流媒体"),
128 128 RECEIVE_STREAM_FAILED(400103,"开启收流失败"),
129   - GET_PLAY_PORT_FAILED(400104,"获取点播端口异常"),
  129 + GET_PLAY_PORT_FAILED(400104,"从流媒体【{}】获取点播端口异常"),
130 130 STREAM_INFO_NOT_FOUND_FOR_PLAY(400105,"点播信息未找到"),
131 131 SIP_COMMAND_SEND_FAILED(400106,"sip命令下发失败"),
132 132 NOT_BELONG_CURRENT_CUSTOMER(400107,"该数据不属于当前客户"),
133 133 IMPORT_ERROR(400108,"请使用模板excel重新导入"),
134 134 INTRANET_ERROR(400109,"内网ip+端口不能重复,请重新输入"),
135 135 OUTER_NET_ERROR(400110,"外网ip+端口不能重复,请重新输入"),
  136 +
  137 + DEVICE_NOT_ONLINE(400111,"设备不在线,无法执行相关操作!"),
136 138 HAVE_NO_PERMISSION(500002,"没有修改权限"),
137 139 NOT_ALLOED_ISOLATED_IN_MONOLITH(500003,"【monolith】模式下,不能选择【isolated】类型的租户配置");
138 140
... ...
... ... @@ -515,6 +515,7 @@ public class SIPProcessorObserver extends SIPRequestProcessorParent
515 515 switch (VideoCmdEnum.valueOf(cmd)) {
516 516 case DeviceInfo:
517 517 SipDeviceDTO cameraInfoDTO = TKXmlUtil.cameraInfoBuilder(rootElement);
  518 + cameraInfoDTO.setHostAddress(request.getViaHost() + ":" + request.getViaPort());
518 519 byte[] cameraMsgBytes = encodingService.encode(cameraInfoDTO);
519 520 msgBuilder.setContext(ByteString.copyFrom(cameraMsgBytes));
520 521 break;
... ... @@ -680,21 +681,7 @@ public class SIPProcessorObserver extends SIPRequestProcessorParent
680 681 .build();
681 682 commanderService.queryDeviceInfo(deviceSessionCtx, deviceInfoHeader);
682 683 int sn = (int) ((Math.random() * 9 + 1) * 100000);
683   - // catalogResponseMessageHandler.setChannelSyncReady(device, sn);
684   - SipMessageHeaderDTO catalogHeader =
685   - SipMessageHeaderDTO.builder()
686   - .viaTag(TKSipUtils.getNewViaTag())
687   - .fromTag(TKSipUtils.getNewFromTag())
688   - .build();
689   - commanderService.queryCatalog(
690   - deviceSessionCtx,
691   - catalogHeader,
692   - sn,
693   - ev -> {
694   - String errorMsg = String.format("同步通道失败,错误码: %s, %s", ev.statusCode, ev.msg);
695   - // catalogResponseMessageHandler.setChannelSyncEnd(device.getDeviceId(),
696   - // errorMsg);
697   - });
  684 + rpcCameraChannel(deviceSessionCtx,sn);
698 685 } catch (InvalidArgumentException | SipException | ParseException e) {
699 686 throw new RuntimeException(e);
700 687 }
... ... @@ -733,6 +720,7 @@ public class SIPProcessorObserver extends SIPRequestProcessorParent
733 720
734 721
735 722
  723 +
736 724 /**
737 725 * 向超时订阅发送消息
738 726 *
... ... @@ -859,14 +847,7 @@ public class SIPProcessorObserver extends SIPRequestProcessorParent
859 847 });
860 848 break;
861 849 case MESSAGE:
862   - SipMessageHeaderDTO controlHeaderDTO =
863   - SipMessageHeaderDTO.builder()
864   - .viaTag(TKSipUtils.getNewViaTag())
865   - .fromTag(TKSipUtils.getNewViaTag())
866   - .toTag(null)
867   - .build();
868   - PTZCmdDTO ptzCmdDTO = JacksonUtil.convertValue(rpcBody.get(FastIotConstants.ZLMediaBody.CONTROL_CONTEXT),PTZCmdDTO.class);
869   - commanderService.controlPtzCmd(channelId,devSession,controlHeaderDTO,ptzCmdDTO);
  850 + toDeviceRpcMessage(devSession,channelId,rpcBody);
870 851 break;
871 852 }
872 853 } catch (InvalidArgumentException | SipException | ParseException e) {
... ... @@ -875,6 +856,47 @@ public class SIPProcessorObserver extends SIPRequestProcessorParent
875 856 }
876 857 }
877 858
  859 + private void toDeviceRpcMessage(GbtDeviceSessionCtx devSession,String channelId,JsonNode rpcBody) throws InvalidArgumentException, ParseException, SipException {
  860 + SipMessageHeaderDTO controlHeaderDTO =
  861 + SipMessageHeaderDTO.builder()
  862 + .viaTag(TKSipUtils.getNewViaTag())
  863 + .fromTag(TKSipUtils.getNewViaTag())
  864 + .toTag(null)
  865 + .build();
  866 + String msgType = rpcBody.get(FastIotConstants.ZLMediaBody.MSG_TYPE).asText();
  867 + switch (VideoXmlEnum.valueOf(msgType)){
  868 + case Control:
  869 + PTZCmdDTO ptzCmdDTO = JacksonUtil.convertValue(rpcBody.get(FastIotConstants.ZLMediaBody.MSG_CONTEXT),PTZCmdDTO.class);
  870 + commanderService.controlPtzCmd(channelId,devSession,controlHeaderDTO,ptzCmdDTO);
  871 + break;
  872 + case Query:
  873 + int sn = rpcBody.get(FastIotConstants.ZLMediaBody.MSG_CONTEXT).intValue();
  874 + rpcCameraChannel(devSession,sn);
  875 + }
  876 + }
  877 +
  878 + /**
  879 + * 查询设备通道信息
  880 + * @throws InvalidArgumentException
  881 + * @throws SipException
  882 + * @throws ParseException
  883 + */
  884 + private void rpcCameraChannel(GbtDeviceSessionCtx deviceSessionCtx,int sn) throws InvalidArgumentException, SipException, ParseException {
  885 + SipMessageHeaderDTO catalogHeader =
  886 + SipMessageHeaderDTO.builder()
  887 + .viaTag(TKSipUtils.getNewViaTag())
  888 + .fromTag(TKSipUtils.getNewFromTag())
  889 + .build();
  890 + commanderService.queryCatalog(
  891 + deviceSessionCtx,
  892 + catalogHeader,
  893 + sn,
  894 + ev -> {
  895 + String errorMsg = String.format("同步通道失败,错误码: %s, %s", ev.statusCode, ev.msg);
  896 + // catalogResponseMessageHandler.setChannelSyncEnd(device.getDeviceId(),
  897 + // errorMsg);
  898 + });
  899 + }
878 900 private String rpcParamVal(JsonNode rpcBody, String key) {
879 901 if (rpcBody.has(key)) {
880 902 return rpcBody.get(key).asText();
... ...
... ... @@ -180,6 +180,7 @@ public class TKXmlUtil {
180 180 cameraInfo.setModel(getText(root, "Model"));
181 181 cameraInfo.setFirmware(getText(root, "Firmware"));
182 182 cameraInfo.setStreamMode("UDP");
  183 + cameraInfo.setTransport("UDP");
183 184 return cameraInfo;
184 185 }
185 186
... ...
... ... @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.yunteng.dto.*;
30 30 import org.thingsboard.server.common.data.yunteng.dto.convert.ConvertConfigDTO;
31 31 import org.thingsboard.server.common.data.yunteng.dto.convert.ConvertDevicesDTO;
32 32 import org.thingsboard.server.common.data.yunteng.dto.convert.DatasourceContentDTO;
  33 +import org.thingsboard.server.common.data.yunteng.dto.sip.SipDeviceDTO;
33 34 import org.thingsboard.server.common.data.yunteng.enums.*;
34 35 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
35 36 import org.thingsboard.server.dao.device.DeviceProfileDao;
... ... @@ -78,10 +79,16 @@ public class TkDeviceServiceImpl extends AbstractBaseService<DeviceMapper, TkDev
78 79 validateUpdate(deviceDTO);
79 80 TkDeviceEntity entity = baseMapper.selectOne(new LambdaQueryWrapper<TkDeviceEntity>().eq(TkDeviceEntity::getTenantId,
80 81 deviceDTO.getTenantId()).eq(TkDeviceEntity::getId,deviceDTO.getId()));
81   - if(null != entity && !entity.getProfileId().equals(deviceDTO.getProfileId())){
82   - //更改了产品,需将原产品的缓存置为无效
83   - cacheUtils.invalidate(cacheName,deviceDTO.getTenantId()+","+entity.getProfileId());
84   - }
  82 + Optional.ofNullable(entity).ifPresent(db->{
  83 + if(!entity.getProfileId().equals(deviceDTO.getProfileId())){
  84 + //更改了产品,需将原产品的缓存置为无效
  85 + cacheUtils.invalidate(cacheName,deviceDTO.getTenantId()+","+entity.getProfileId());
  86 + }
  87 + Optional.ofNullable(db.getDeviceInfo().get(FastIotConstants.DeviceAdditional.SIP)).ifPresent(sip ->{
  88 + ObjectNode additional = (ObjectNode) deviceDTO.getDeviceInfo();
  89 + additional.set(FastIotConstants.DeviceAdditional.SIP,sip);
  90 + });
  91 + });
85 92 TkDeviceEntity device = new TkDeviceEntity();
86 93 deviceDTO.copyToEntity(
87 94 device,
... ...