Merge branch 'master' into dev/zlm
# Conflicts:
# src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
# src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
# src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java
# src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java
# src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java
| | |
| | | [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 |
| | | |
| | |  |
| | |
| | | @Schema(description = "æ¯å¦ä½ä¸ºæ¶æ¯éé") |
| | | private boolean autoPushChannel; |
| | | |
| | | @Schema(description = "ç¹æåå¤200OKä½¿ç¨æ¬¡IP") |
| | | private String sendStreamIp; |
| | | |
| | | public Integer getId() { |
| | | return id; |
| | | } |
| | |
| | | public void setAutoPushChannel(boolean autoPushChannel) { |
| | | this.autoPushChannel = autoPushChannel; |
| | | } |
| | | |
| | | public String getSendStreamIp() { |
| | | return sendStreamIp; |
| | | } |
| | | |
| | | public void setSendStreamIp(String sendStreamIp) { |
| | | this.sendStreamIp = sendStreamIp; |
| | | } |
| | | } |
| | |
| | | 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 + '\'' + |
| | | '}'; |
| | | } |
| | | } |
| | |
| | | |
| | | 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(), |
| | |
| | | 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; |
| | |
| | | // * 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 { |
| | |
| | | } |
| | | |
| | | 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) { |
| | | // ä»redisæ¥è¯¢æ¯å¦æ£å¨æ¥æ¶è¿ä¸ªæ¨æµ |
| | | 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) { |
| | |
| | | |
| | | public SIPResponse sendStreamAck(MediaServer 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"); |
| | | // éä¸¥æ ¼æ¨¡å¼ç«¯å£ä¸ç»ä¸, å¢å å
¼å®¹æ§ï¼ä¿®æ¹ä¸ºä¸ä¸ªä¸ä¸º0çç«¯å£ |
| | | int localPort = sendRtpItem.getLocalPort(); |
| | |
| | | dynamicTask.startDelay(key, ()->{ |
| | | logger.info("[è¯é³å¹¿æ]çå¾
inviteæ¶æ¯è¶
æ¶ï¼{}/{}", device.getDeviceId(), channelId); |
| | | stopAudioBroadcast(device.getDeviceId(), channelId); |
| | | }, 2000); |
| | | }, 10*1000); |
| | | }, eventResultForError -> { |
| | | // åé失败 |
| | | logger.error("è¯é³å¹¿æåéå¤±è´¥ï¼ {}:{}", channelId, eventResultForError.msg); |
| | |
| | | |
| | | 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 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; |
| | |
| | | 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; |
| | |
| | | |
| | | @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 æµåå]æ¶æ¯è§£æå¤±è´¥"); |
| | | 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 æµåå]æ¶æ¯è§£æå¤±è´¥"); |
| | | // 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); |
| | | // } |
| | | // } |
| | | // }); |
| | | // } |
| | | } |
| | | } |
| | |
| | | |
| | | void addPushListItem(String app, String stream, MediaArrivalEvent param); |
| | | |
| | | OnStreamChangedHookParam getPushListItem(String app, String stream); |
| | | |
| | | void removePushListItem(String app, String stream, String mediaServerId); |
| | | |
| | | void sendPushStreamClose(MessageForPushChannel messageForPushChannel); |
| | | |
| | | } |
| | |
| | | |
| | | @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 " + |
| | |
| | | "administrative_division=#{administrativeDivision}, " + |
| | | "create_time=#{createTime}, " + |
| | | "update_time=#{updateTime}, " + |
| | | "send_stream_ip=#{sendStreamIp}, " + |
| | | "catalog_id=#{catalogId} " + |
| | | "WHERE id=#{id}") |
| | | int updateParentPlatform(ParentPlatform parentPlatform); |
| | |
| | | } |
| | | |
| | | @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); |
| | |
| | | } |
| | | |
| | | } |
| | | |
| | | @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)); |
| | | } |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| | | import com.genersoft.iot.vmp.conf.security.JwtUtils; |
| | | import com.genersoft.iot.vmp.media.bean.MediaServer; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| | | import com.genersoft.iot.vmp.service.ICloudRecordService; |
| | | import com.genersoft.iot.vmp.media.service.IMediaServerService; |
| | | import com.genersoft.iot.vmp.service.bean.CloudRecordItem; |
| | |
| | | wvpResult.setMsg(msg); |
| | | } |
| | | requestMessage.setData(wvpResult); |
| | | resultHolder.invokeResult(requestMessage); |
| | | // æ¤å¤å¿
须鿾ææè¯·æ± |
| | | resultHolder.invokeAllResult(requestMessage); |
| | | }); |
| | | return result; |
| | | } |
| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | characterSet: "GB2312", |
| | | startOfflinePush: false, |
| | | catalogGroup: 1, |
| | | administrativeDivision: null, |
| | | administrativeDivision: "", |
| | | sendStreamIp: null, |
| | | }, |
| | | rules: { |
| | | name: [{ required: true, message: "请è¾å
¥å¹³å°åç§°", trigger: "blur" }], |
| | |
| | | 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); |
| | | } |
| | | |
| | |
| | | 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"; |
| | |
| | | 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) |
| | | ); |
| | | |
| | |
| | | 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) |
| | | ); |
| | | |
| | |
| | | add stream_identification character varying(50); |
| | | |
| | | alter table wvp_device |
| | | drop switch_primary_sub_stream; |
| | | drop switch_primary_sub_stream; |
| | | |
| | | alter table wvp_platform |
| | | add send_stream_ip character varying(50); |
| | |
| | | add stream_identification character varying(50); |
| | | |
| | | alter table wvp_device |
| | | drop switch_primary_sub_stream; |
| | | drop switch_primary_sub_stream; |
| | | |
| | | alter table wvp_platform |
| | | add send_stream_ip character varying(50); |