From b6d70c680751128173c820c37712dd317ddb9b72 Mon Sep 17 00:00:00 2001 From: leesam <leesam@leesam.cn> Date: 星期二, 09 四月 2024 09:59:06 +0800 Subject: [PATCH] Merge branch 'develop-add-api-key' of https://github.com/ancienter/wvp-GB28181-pro into develop-add-api-key --- web_src/src/components/dialog/platformEdit.vue | 12 + src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java | 11 + src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java | 29 ++++ src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java | 1 src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java | 28 +++ src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java | 5 src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java | 98 ++++++------- 数据库/2.7.0/初始化-postgresql-kingbase-2.7.0.sql | 1 src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java | 5 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java | 2 README.md | 10 - src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java | 40 +++- src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java | 5 数据库/2.7.0/更新-mysql-2.7.0.sql | 5 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java | 56 +++++--- src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java | 13 + src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java | 5 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java | 31 --- 数据库/2.7.0/初始化-mysql-2.7.0.sql | 1 src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java | 23 --- src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java | 4 src/main/java/com/genersoft/iot/vmp/service/IPlayService.java | 1 数据库/2.7.0/更新-postgresql-kingbase-2.7.0.sql | 5 23 files changed, 227 insertions(+), 164 deletions(-) diff --git a/README.md b/README.md index a50c36d..df71b6c 100644 --- a/README.md +++ b/README.md @@ -136,12 +136,6 @@ [ydpd](https://github.com/ydpd) [szy833](https://github.com/szy833) [ydwxb](https://github.com/ydwxb) [Albertzhu666](https://github.com/Albertzhu666) [mk1990](https://github.com/mk1990) [SaltFish001](https://github.com/SaltFish001) +鍚屾椂鎰熻阿JetBrains瀵瑰紑婧愰」鐩殑鏀寔锛屾湰椤圭洰浣跨敤IntelliJ IDEA寮�鍙戜笌璋冭瘯锛� -ffmpeg -re -i 123.mp3 -acodec pcm_alaw -ar 8000 -ac 1 -f rtsp rtsp://192.168.1.3:30554/broadcast/34020000001320000101_34020000001310000001 - -ffmpeg -re -i 123.mp3 -acodec pcm_alaw -ar 8000 -ac 1 -f rtsp rtsp://192.168.1.3:30554/talk/34020000001320000011_34020000001370000001 - - - -ffmpeg -re -i 123.mp3 -acodec pcm_alaw -ar 8000 -ac 1 -f rtsp rtsp://192.168.1.3:30554/talk/34020000001320000101_34020000001310000001 - + diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java index 7de5098..5de9761 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java @@ -189,6 +189,9 @@ @Schema(description = "鏄惁浣滀负娑堟伅閫氶亾") private boolean autoPushChannel; + @Schema(description = "鐐规挱鍥炲200OK浣跨敤娆P") + private String sendStreamIp; + public Integer getId() { return id; } @@ -436,4 +439,12 @@ public void setAutoPushChannel(boolean autoPushChannel) { this.autoPushChannel = autoPushChannel; } + + public String getSendStreamIp() { + return sendStreamIp; + } + + public void setSendStreamIp(String sendStreamIp) { + this.sendStreamIp = sendStreamIp; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java index 361bdc6..30193d2 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java @@ -305,4 +305,33 @@ public void setReceiveStream(String receiveStream) { this.receiveStream = receiveStream; } + + @Override + public String toString() { + return "SendRtpItem{" + + "ip='" + ip + '\'' + + ", port=" + port + + ", ssrc='" + ssrc + '\'' + + ", platformId='" + platformId + '\'' + + ", deviceId='" + deviceId + '\'' + + ", app='" + app + '\'' + + ", channelId='" + channelId + '\'' + + ", status=" + status + + ", stream='" + stream + '\'' + + ", tcp=" + tcp + + ", tcpActive=" + tcpActive + + ", localPort=" + localPort + + ", mediaServerId='" + mediaServerId + '\'' + + ", serverId='" + serverId + '\'' + + ", CallId='" + CallId + '\'' + + ", fromTag='" + fromTag + '\'' + + ", toTag='" + toTag + '\'' + + ", pt=" + pt + + ", usePs=" + usePs + + ", onlyAudio=" + onlyAudio + + ", rtcp=" + rtcp + + ", playType=" + playType + + ", receiveStream='" + receiveStream + '\'' + + '}'; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java index 7004820..242e5ef 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java @@ -116,7 +116,7 @@ if (parentPlatform != null) { Map<String, Object> param = getSendRtpParam(sendRtpItem); - if (mediaInfo == null) { + if (!userSetting.getServerId().equals(sendRtpItem.getServerId())) { RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance( sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), sendRtpItem.getSsrc(), sendRtpItem.isTcp(), diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index 3205498..96b8b11 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -38,6 +38,7 @@ import gov.nist.javax.sdp.fields.URIField; import gov.nist.javax.sip.message.SIPRequest; import gov.nist.javax.sip.message.SIPResponse; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -404,12 +405,15 @@ // * 2 鎺ㄦ祦涓� sendRtpItem.setStatus(1); redisCatchStorage.updateSendRTPSever(sendRtpItem); - + String sdpIp = mediaServerItemInUSe.getSdpIp(); + if (!ObjectUtils.isEmpty(platform.getSendStreamIp())) { + sdpIp = platform.getSendStreamIp(); + } StringBuffer content = new StringBuffer(200); content.append("v=0\r\n"); - content.append("o=" + channelId + " 0 0 IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n"); + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); content.append("s=" + sessionName + "\r\n"); - content.append("c=IN IP4 " + mediaServerItemInUSe.getSdpIp() + "\r\n"); + content.append("c=IN IP4 " + sdpIp + "\r\n"); if ("Playback".equalsIgnoreCase(sessionName)) { content.append("t=" + finalStartTime + " " + finalStopTime + "\r\n"); } else { @@ -575,14 +579,20 @@ } if ("push".equals(gbStream.getStreamType())) { - if (streamPushItem != null && streamPushItem.isPushIng()) { - // 鎺ㄦ祦鐘舵�� - pushStream(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, - mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); - } else { - // 鏈帹娴� 鎷夎捣 - notifyStreamOnline(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, - mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); + if (streamPushItem != null) { + // 浠巖edis鏌ヨ鏄惁姝e湪鎺ユ敹杩欎釜鎺ㄦ祦 + OnStreamChangedHookParam pushListItem = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream()); + if (pushListItem != null) { + StreamPushItem transform = streamPushService.transform(pushListItem); + transform.setSelf(userSetting.getServerId().equals(pushListItem.getSeverId())); + // 鎺ㄦ祦鐘舵�� + pushStream(evt, request, gbStream, transform, platform, callIdHeader, mediaServerItem, port, tcpActive, + mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); + }else { + // 鏈帹娴� 鎷夎捣 + notifyStreamOnline(evt, request, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive, + mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); + } } } else if ("proxy".equals(gbStream.getStreamType())) { if (null != proxyByAppAndStream) { @@ -901,11 +911,15 @@ public SIPResponse sendStreamAck(MediaServerItem mediaServerItem, SIPRequest request, SendRtpItem sendRtpItem, ParentPlatform platform, RequestEvent evt) { + String sdpIp = mediaServerItem.getSdpIp(); + if (!ObjectUtils.isEmpty(platform.getSendStreamIp())) { + sdpIp = platform.getSendStreamIp(); + } StringBuffer content = new StringBuffer(200); content.append("v=0\r\n"); - content.append("o=" + sendRtpItem.getChannelId() + " 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); + content.append("o=" + sendRtpItem.getChannelId() + " 0 0 IN IP4 " + sdpIp + "\r\n"); content.append("s=Play\r\n"); - content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); + content.append("c=IN IP4 " + sdpIp + "\r\n"); content.append("t=0 0\r\n"); // 闈炰弗鏍兼ā寮忕鍙d笉缁熶竴, 澧炲姞鍏煎鎬э紝淇敼涓轰竴涓笉涓�0鐨勭鍙� int localPort = sendRtpItem.getLocalPort(); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index 5feb306..6076db4 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -509,32 +509,46 @@ List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream()); if (!sendRtpItems.isEmpty()) { for (SendRtpItem sendRtpItem : sendRtpItems) { - if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) { - String platformId = sendRtpItem.getPlatformId(); - ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); - Device device = deviceService.getDevice(platformId); + if (sendRtpItem == null) { + continue; + } - try { - if (platform != null) { - commanderFroPlatform.streamByeCmd(platform, sendRtpItem); - redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), - sendRtpItem.getCallId(), sendRtpItem.getStream()); - } else { - cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); - if (sendRtpItem.getPlayType().equals(InviteStreamType.BROADCAST) - || sendRtpItem.getPlayType().equals(InviteStreamType.TALK)) { - AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); - if (audioBroadcastCatch != null) { - // 鏉ヨ嚜涓婄骇骞冲彴鐨勫仠姝㈠璁� - logger.info("[鍋滄瀵硅] 鏉ヨ嚜涓婄骇锛屽钩鍙帮細{}, 閫氶亾锛歿}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); - audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); + if (sendRtpItem.getApp().equals(param.getApp())) { + logger.info(sendRtpItem.toString()); + if (userSetting.getServerId().equals(sendRtpItem.getServerId())) { + MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, + sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(), + sendRtpItem.getPlatformId(), null, userSetting.getServerId(), param.getMediaServerId()); + // 閫氱煡鍏朵粬wvp鍋滄鍙戞祦 + redisCatchStorage.sendPushStreamClose(messageForPushChannel); + }else { + String platformId = sendRtpItem.getPlatformId(); + ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); + Device device = deviceService.getDevice(platformId); + + try { + if (platform != null) { + commanderFroPlatform.streamByeCmd(platform, sendRtpItem); + redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), + sendRtpItem.getCallId(), sendRtpItem.getStream()); + } else { + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId()); + if (sendRtpItem.getPlayType().equals(InviteStreamType.BROADCAST) + || sendRtpItem.getPlayType().equals(InviteStreamType.TALK)) { + AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); + if (audioBroadcastCatch != null) { + // 鏉ヨ嚜涓婄骇骞冲彴鐨勫仠姝㈠璁� + logger.info("[鍋滄瀵硅] 鏉ヨ嚜涓婄骇锛屽钩鍙帮細{}, 閫氶亾锛歿}", sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); + audioBroadcastManager.del(sendRtpItem.getDeviceId(), sendRtpItem.getChannelId()); + } } } + } catch (SipException | InvalidArgumentException | ParseException | + SsrcTransactionNotFoundException e) { + logger.error("[鍛戒护鍙戦�佸け璐 鍙戦�丅YE: {}", e.getMessage()); } - } catch (SipException | InvalidArgumentException | ParseException | - SsrcTransactionNotFoundException e) { - logger.error("[鍛戒护鍙戦�佸け璐 鍙戦�丅YE: {}", e.getMessage()); } + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java b/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java index c690f11..16ff831 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java @@ -98,4 +98,5 @@ void updateChannelGPS(Device device, DeviceChannel deviceChannel, MobilePosition mobilePosition); + void stopPlay(String deviceId, String channelId); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java index 77525e8..bb2e2be 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java @@ -68,4 +68,5 @@ void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback); + void stopPlay(Device device, String channelId); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java index 632be91..6807632 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java @@ -353,4 +353,9 @@ redisCatchStorage.sendMobilePositionMsg(jsonObject); } } + + @Override + public void stopPlay(String deviceId, String channelId) { + channelMapper.stopPlay(deviceId, channelId); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index c8d203f..9bd0547 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -34,7 +34,6 @@ import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; -import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; import com.genersoft.iot.vmp.utils.CloudRecordUtils; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; @@ -122,9 +121,6 @@ @Autowired private DynamicTask dynamicTask; - - @Autowired - private CloudRecordServiceMapper cloudRecordServiceMapper; @Autowired private ISIPCommanderForPlatform commanderForPlatform; @@ -1170,7 +1166,7 @@ dynamicTask.startDelay(key, ()->{ logger.info("[璇煶骞挎挱]绛夊緟invite娑堟伅瓒呮椂锛歿}/{}", device.getDeviceId(), channelId); stopAudioBroadcast(device.getDeviceId(), channelId); - }, 2000); + }, 10*1000); }, eventResultForError -> { // 鍙戦�佸け璐� logger.error("璇煶骞挎挱鍙戦�佸け璐ワ細 {}:{}", channelId, eventResultForError.msg); @@ -1592,4 +1588,26 @@ }); } + @Override + public void stopPlay(Device device, String channelId) { + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId); + if (inviteInfo == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "鐐规挱鏈壘鍒�"); + } + if (InviteSessionStatus.ok == inviteInfo.getStatus()) { + try { + logger.info("[鍋滄鐐规挱] {}/{}", device.getDeviceId(), channelId); + cmder.streamByeCmd(device, channelId, inviteInfo.getStream(), null, null); + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { + logger.error("[鍛戒护鍙戦�佸け璐 鍋滄鐐规挱锛� 鍙戦�丅YE: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "鍛戒护鍙戦�佸け璐�: " + e.getMessage()); + } + } + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId); + storager.stopPlay(device.getDeviceId(), channelId); + channelService.stopPlay(device.getDeviceId(), channelId); + if (inviteInfo.getStreamInfo() != null) { + mediaServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServerId(), inviteInfo.getStream()); + } + } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java index 59c5ace..f0230f7 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java @@ -8,7 +8,6 @@ import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; -import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; @@ -25,7 +24,6 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.storager.dao.GbStreamMapper; -import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper; import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper; import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper; import com.genersoft.iot.vmp.utils.DateUtil; @@ -333,8 +331,6 @@ result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl().trim(), param.isEnableAudio(), param.isEnableMp4(), param.getRtpType()); } - System.out.println("addStreamProxyToZlm===="); - System.out.println(result); if (result != null && result.getInteger("code") == 0) { JSONObject data = result.getJSONObject("data"); if (data == null) { diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java index fe0ccd2..a031573 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java @@ -2,12 +2,10 @@ import com.alibaba.fastjson2.JSON; import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.service.IStreamPushService; @@ -25,7 +23,6 @@ import javax.sip.InvalidArgumentException; import javax.sip.SipException; import java.text.ParseException; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -84,26 +81,6 @@ commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem); } catch (SipException | InvalidArgumentException | ParseException e) { logger.error("[鍛戒护鍙戦�佸け璐 鍥芥爣绾ц仈 鍙戦�丅YE: {}", e.getMessage()); - } - } - if (push.isSelf()) { - // 鍋滄鍚戜笂绾ф帹娴� - String streamId = sendRtpItem.getStream(); - Map<String, Object> param = new HashMap<>(); - param.put("vhost","__defaultVhost__"); - param.put("app",sendRtpItem.getApp()); - param.put("stream",streamId); - param.put("ssrc",sendRtpItem.getSsrc()); - logger.info("[REDIS娑堟伅-鎺ㄦ祦缁撴潫] 鍋滄鍚戜笂绾ф帹娴侊細{}", streamId); - MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId()); - redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(), sendRtpItem.getChannelId(), sendRtpItem.getCallId(), sendRtpItem.getStream()); - zlmServerFactory.stopSendRtpStream(mediaInfo, param); - if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) { - MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0, - sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getChannelId(), - sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId()); - messageForPushChannel.setPlatFormIndex(parentPlatform.getId()); - redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java index f5f2948..0912f0b 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java @@ -1,11 +1,7 @@ package com.genersoft.iot.vmp.service.redisMsg; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.conf.UserSetting; - import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager; -import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -41,52 +37,52 @@ @Override public void onMessage(Message message, byte[] bytes) { - boolean isEmpty = taskQueue.isEmpty(); - taskQueue.offer(message); - if (isEmpty) { - taskExecutor.execute(() -> { - while (!taskQueue.isEmpty()) { - Message msg = taskQueue.poll(); - try { - JSONObject steamMsgJson = JSON.parseObject(msg.getBody(), JSONObject.class); - if (steamMsgJson == null) { - logger.warn("[鏀跺埌redis 娴佸彉鍖朷娑堟伅瑙f瀽澶辫触"); - continue; - } - String serverId = steamMsgJson.getString("serverId"); - - if (userSetting.getServerId().equals(serverId)) { - // 鑷繁鍙戦�佺殑娑堟伅蹇界暐鍗冲彲 - continue; - } - logger.info("[鏀跺埌redis 娴佸彉鍖朷锛� {}", new String(message.getBody())); - String app = steamMsgJson.getString("app"); - String stream = steamMsgJson.getString("stream"); - boolean register = steamMsgJson.getBoolean("register"); - String mediaServerId = steamMsgJson.getString("mediaServerId"); - OnStreamChangedHookParam onStreamChangedHookParam = new OnStreamChangedHookParam(); - onStreamChangedHookParam.setSeverId(serverId); - onStreamChangedHookParam.setApp(app); - onStreamChangedHookParam.setStream(stream); - onStreamChangedHookParam.setRegist(register); - onStreamChangedHookParam.setMediaServerId(mediaServerId); - onStreamChangedHookParam.setCreateStamp(System.currentTimeMillis()/1000); - onStreamChangedHookParam.setAliveSecond(0L); - onStreamChangedHookParam.setTotalReaderCount("0"); - onStreamChangedHookParam.setOriginType(0); - onStreamChangedHookParam.setOriginTypeStr("0"); - onStreamChangedHookParam.setOriginTypeStr("unknown"); - if (register) { - zlmMediaListManager.addPush(onStreamChangedHookParam); - }else { - zlmMediaListManager.removeMedia(app, stream); - } - }catch (Exception e) { - logger.warn("[REDIS娑堟伅-娴佸彉鍖朷 鍙戠幇鏈鐞嗙殑寮傚父, \r\n{}", JSON.toJSONString(message)); - logger.error("[REDIS娑堟伅-娴佸彉鍖朷 寮傚父鍐呭锛� ", e); - } - } - }); - } +// boolean isEmpty = taskQueue.isEmpty(); +// taskQueue.offer(message); +// if (isEmpty) { +// taskExecutor.execute(() -> { +// while (!taskQueue.isEmpty()) { +// Message msg = taskQueue.poll(); +// try { +// JSONObject steamMsgJson = JSON.parseObject(msg.getBody(), JSONObject.class); +// if (steamMsgJson == null) { +// logger.warn("[鏀跺埌redis 娴佸彉鍖朷娑堟伅瑙f瀽澶辫触"); +// continue; +// } +// String serverId = steamMsgJson.getString("serverId"); +// +// if (userSetting.getServerId().equals(serverId)) { +// // 鑷繁鍙戦�佺殑娑堟伅蹇界暐鍗冲彲 +// continue; +// } +// logger.info("[鏀跺埌redis 娴佸彉鍖朷锛� {}", new String(message.getBody())); +// String app = steamMsgJson.getString("app"); +// String stream = steamMsgJson.getString("stream"); +// boolean register = steamMsgJson.getBoolean("register"); +// String mediaServerId = steamMsgJson.getString("mediaServerId"); +// OnStreamChangedHookParam onStreamChangedHookParam = new OnStreamChangedHookParam(); +// onStreamChangedHookParam.setSeverId(serverId); +// onStreamChangedHookParam.setApp(app); +// onStreamChangedHookParam.setStream(stream); +// onStreamChangedHookParam.setRegist(register); +// onStreamChangedHookParam.setMediaServerId(mediaServerId); +// onStreamChangedHookParam.setCreateStamp(System.currentTimeMillis()/1000); +// onStreamChangedHookParam.setAliveSecond(0L); +// onStreamChangedHookParam.setTotalReaderCount("0"); +// onStreamChangedHookParam.setOriginType(0); +// onStreamChangedHookParam.setOriginTypeStr("0"); +// onStreamChangedHookParam.setOriginTypeStr("unknown"); +// if (register) { +// zlmMediaListManager.addPush(onStreamChangedHookParam); +// }else { +// zlmMediaListManager.removeMedia(app, stream); +// } +// }catch (Exception e) { +// logger.warn("[REDIS娑堟伅-娴佸彉鍖朷 鍙戠幇鏈鐞嗙殑寮傚父, \r\n{}", JSON.toJSONString(message)); +// logger.error("[REDIS娑堟伅-娴佸彉鍖朷 寮傚父鍐呭锛� ", e); +// } +// } +// }); +// } } } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java index 78fd280..66db103 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java @@ -211,5 +211,10 @@ void addPushListItem(String app, String stream, OnStreamChangedHookParam param); + OnStreamChangedHookParam getPushListItem(String app, String stream); + void removePushListItem(String app, String stream, String mediaServerId); + + void sendPushStreamClose(MessageForPushChannel messageForPushChannel); + } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java index 9dc0503..63b19bb 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java @@ -17,10 +17,10 @@ @Insert("INSERT INTO wvp_platform (enable, name, server_gb_id, server_gb_domain, server_ip, server_port,device_gb_id,device_ip,"+ "device_port,username,password,expires,keep_timeout,transport,character_set,ptz,rtcp,as_message_channel,auto_push_channel,"+ - "status,start_offline_push,catalog_id,administrative_division,catalog_group,create_time,update_time) " + + "status,start_offline_push,catalog_id,administrative_division,catalog_group,create_time,update_time,send_stream_ip) " + " VALUES (#{enable}, #{name}, #{serverGBId}, #{serverGBDomain}, #{serverIP}, #{serverPort}, #{deviceGBId}, #{deviceIp}, " + " #{devicePort}, #{username}, #{password}, #{expires}, #{keepTimeout}, #{transport}, #{characterSet}, #{ptz}, #{rtcp}, #{asMessageChannel}, #{autoPushChannel}, " + - " #{status}, #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime})") + " #{status}, #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{sendStreamIp})") int addParentPlatform(ParentPlatform parentPlatform); @Update("UPDATE wvp_platform " + @@ -49,6 +49,7 @@ "administrative_division=#{administrativeDivision}, " + "create_time=#{createTime}, " + "update_time=#{updateTime}, " + + "send_stream_ip=#{sendStreamIp}, " + "catalog_id=#{catalogId} " + "WHERE id=#{id}") int updateParentPlatform(ParentPlatform parentPlatform); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java index 18a037d..1eac4df 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java @@ -657,6 +657,12 @@ } @Override + public OnStreamChangedHookParam getPushListItem(String app, String stream) { + String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream; + return (OnStreamChangedHookParam)redisTemplate.opsForValue().get(key); + } + + @Override public void removePushListItem(String app, String stream, String mediaServerId) { String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream; OnStreamChangedHookParam param = (OnStreamChangedHookParam)redisTemplate.opsForValue().get(key); @@ -665,4 +671,11 @@ } } + + @Override + public void sendPushStreamClose(MessageForPushChannel msg) { + String key = VideoManagerConstants.VM_MSG_STREAM_PUSH_CLOSE_REQUESTED; + logger.info("[redis鍙戦�侀�氱煡] 鍙戦�� 鍋滄鍚戜笂绾ф帹娴� {}: {}/{}->{}", key, msg.getApp(), msg.getStream(), msg.getPlatFormId()); + redisTemplate.convertAndSend(key, JSON.toJSON(msg)); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java index b3d1990..b37a3d9 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java @@ -1,12 +1,8 @@ package com.genersoft.iot.vmp.vmanager.cloudRecord; import com.alibaba.fastjson2.JSONArray; -import com.genersoft.iot.vmp.conf.DynamicTask; -import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.security.JwtUtils; -import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; -import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.service.ICloudRecordService; import com.genersoft.iot.vmp.service.IMediaServerService; @@ -22,7 +18,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java index ca8cbcf..97a5baa 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java @@ -3,12 +3,10 @@ import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.common.InviteInfo; -import com.genersoft.iot.vmp.common.InviteSessionStatus; import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.conf.security.JwtUtils; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; @@ -26,7 +24,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.utils.DateUtil; -import com.genersoft.iot.vmp.vmanager.bean.*; +import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; @@ -41,11 +39,8 @@ import org.springframework.web.context.request.async.DeferredResult; import javax.servlet.http.HttpServletRequest; -import javax.sip.InvalidArgumentException; -import javax.sip.SipException; import java.net.MalformedURLException; import java.net.URL; -import java.text.ParseException; import java.util.List; import java.util.UUID; @@ -157,7 +152,8 @@ wvpResult.setMsg(msg); } requestMessage.setData(wvpResult); - resultHolder.invokeResult(requestMessage); + // 姝ゅ蹇呴』閲婃斁鎵�鏈夎姹� + resultHolder.invokeAllResult(requestMessage); }); return result; } @@ -165,9 +161,8 @@ @Operation(summary = "鍋滄鐐规挱", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "璁惧鍥芥爣缂栧彿", required = true) @Parameter(name = "channelId", description = "閫氶亾鍥芥爣缂栧彿", required = true) - @Parameter(name = "isSubStream", description = "鏄惁瀛愮爜娴侊紙true-瀛愮爜娴侊紝false-涓荤爜娴侊級锛岄粯璁や负false", required = true) @GetMapping("/stop/{deviceId}/{channelId}") - public JSONObject playStop(@PathVariable String deviceId, @PathVariable String channelId,boolean isSubStream) { + public JSONObject playStop(@PathVariable String deviceId, @PathVariable String channelId) { logger.debug(String.format("璁惧棰勮/鍥炴斁鍋滄API璋冪敤锛宻treamId锛�%s_%s", deviceId, channelId )); @@ -180,26 +175,10 @@ throw new ControllerException(ErrorCode.ERROR100.getCode(), "璁惧[" + deviceId + "]涓嶅瓨鍦�"); } - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); - if (inviteInfo == null) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "鐐规挱鏈壘鍒�"); - } - if (InviteSessionStatus.ok == inviteInfo.getStatus()) { - try { - logger.info("[鍋滄鐐规挱] {}/{}", device.getDeviceId(), channelId); - cmder.streamByeCmd(device, channelId, inviteInfo.getStream(), null, null); - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { - logger.error("[鍛戒护鍙戦�佸け璐 鍋滄鐐规挱锛� 鍙戦�丅YE: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "鍛戒护鍙戦�佸け璐�: " + e.getMessage()); - } - } - inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); - storager.stopPlay(deviceId, channelId); - + playService.stopPlay(device, channelId); JSONObject json = new JSONObject(); json.put("deviceId", deviceId); json.put("channelId", channelId); - json.put("isSubStream", isSubStream); return json; } diff --git a/web_src/src/components/dialog/platformEdit.vue b/web_src/src/components/dialog/platformEdit.vue index f3f4255..4c02dfc 100755 --- a/web_src/src/components/dialog/platformEdit.vue +++ b/web_src/src/components/dialog/platformEdit.vue @@ -37,8 +37,8 @@ <el-form-item label="鏈湴绔彛" prop="devicePort"> <el-input v-model="platform.devicePort" :disabled="true" type="number"></el-input> </el-form-item> - <el-form-item label="SIP璁よ瘉鐢ㄦ埛鍚�" prop="username"> - <el-input v-model="platform.username"></el-input> + <el-form-item label="SDP鍙戞祦IP" prop="sendStreamIp"> + <el-input v-model="platform.sendStreamIp"></el-input> </el-form-item> </el-form> </el-col> @@ -46,6 +46,9 @@ <el-form ref="platform2" :rules="rules" :model="platform" label-width="160px"> <el-form-item label="琛屾斂鍖哄垝" prop="administrativeDivision"> <el-input v-model="platform.administrativeDivision" clearable></el-input> + </el-form-item> + <el-form-item label="SIP璁よ瘉鐢ㄦ埛鍚�" prop="username"> + <el-input v-model="platform.username"></el-input> </el-form-item> <el-form-item label="SIP璁よ瘉瀵嗙爜" prop="password"> <el-input v-model="platform.password" ></el-input> @@ -159,7 +162,8 @@ characterSet: "GB2312", startOfflinePush: false, catalogGroup: 1, - administrativeDivision: null, + administrativeDivision: "", + sendStreamIp: null, }, rules: { name: [{ required: true, message: "璇疯緭鍏ュ钩鍙板悕绉�", trigger: "blur" }], @@ -198,6 +202,7 @@ that.platform.devicePort = res.data.data.devicePort; that.platform.username = res.data.data.username; that.platform.password = res.data.data.password; + that.platform.sendStreamIp = res.data.data.sendStreamIp; that.platform.administrativeDivision = res.data.data.username.substr(0, 6); } @@ -228,6 +233,7 @@ this.platform.catalogId = platform.catalogId; this.platform.startOfflinePush = platform.startOfflinePush; this.platform.catalogGroup = platform.catalogGroup; + this.platform.sendStreamIp = platform.sendStreamIp; this.platform.administrativeDivision = platform.administrativeDivision; this.onSubmit_text = "淇濆瓨"; this.saveUrl = "/api/platform/save"; diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql" index 6e1f83b..edab7dc 100644 --- "a/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql" +++ "b/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql" @@ -198,6 +198,7 @@ update_time character varying(50), as_message_channel bool default false, auto_push_channel bool default false, + send_stream_ip character varying(50), constraint uk_platform_unique_server_gb_id unique (server_gb_id) ); diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql" index 17ef270..452c36c 100644 --- "a/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql" +++ "b/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql" @@ -198,6 +198,7 @@ update_time character varying(50), as_message_channel bool default false, auto_push_channel bool default false, + send_stream_ip character varying(50), constraint uk_platform_unique_server_gb_id unique (server_gb_id) ); diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-mysql-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-mysql-2.7.0.sql" index 141c26e..c229fb1 100644 --- "a/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-mysql-2.7.0.sql" +++ "b/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-mysql-2.7.0.sql" @@ -2,4 +2,7 @@ add stream_identification character varying(50); alter table wvp_device - drop switch_primary_sub_stream; \ No newline at end of file + drop switch_primary_sub_stream; + +alter table wvp_platform + add send_stream_ip character varying(50); \ No newline at end of file diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql" index 141c26e..c229fb1 100644 --- "a/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql" +++ "b/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql" @@ -2,4 +2,7 @@ add stream_identification character varying(50); alter table wvp_device - drop switch_primary_sub_stream; \ No newline at end of file + drop switch_primary_sub_stream; + +alter table wvp_platform + add send_stream_ip character varying(50); \ No newline at end of file -- Gitblit v1.8.0