Commit 509d9b3cbba7ba8fdc7466c34e46db70d41517a8
Merge branch 'wvp-28181-2.0' into main-dev
# Conflicts: # src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java # src/main/java/com/genersoft/iot/vmp/service/IPlayService.java # src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java # src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
Showing
32 changed files
with
1104 additions
and
253 deletions
README.md
| @@ -49,6 +49,7 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git | @@ -49,6 +49,7 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git | ||
| 49 | - [X] 支持电子地图,支持接入WGS84和GCJ02两种坐标系,并且自动转化为合适的坐标系进行展示和分发 | 49 | - [X] 支持电子地图,支持接入WGS84和GCJ02两种坐标系,并且自动转化为合适的坐标系进行展示和分发 |
| 50 | - [X] 接入设备 | 50 | - [X] 接入设备 |
| 51 | - [X] 视频预览 | 51 | - [X] 视频预览 |
| 52 | + - [X] 支持主码流子码流切换 | ||
| 52 | - [X] 无限制接入路数,能接入多少设备只取决于你的服务器性能 | 53 | - [X] 无限制接入路数,能接入多少设备只取决于你的服务器性能 |
| 53 | - [X] 云台控制,控制设备转向,拉近,拉远 | 54 | - [X] 云台控制,控制设备转向,拉近,拉远 |
| 54 | - [X] 预置位查询,使用与设置 | 55 | - [X] 预置位查询,使用与设置 |
src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java
| 1 | package com.genersoft.iot.vmp.common; | 1 | package com.genersoft.iot.vmp.common; |
| 2 | 2 | ||
| 3 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; | 3 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | 4 | ||
| 6 | /** | 5 | /** |
| 7 | * 记录每次发送invite消息的状态 | 6 | * 记录每次发送invite消息的状态 |
| @@ -125,20 +124,4 @@ public class InviteInfo { | @@ -125,20 +124,4 @@ public class InviteInfo { | ||
| 125 | this.streamMode = streamMode; | 124 | this.streamMode = streamMode; |
| 126 | } | 125 | } |
| 127 | 126 | ||
| 128 | - | ||
| 129 | - /*=========================设备主子码流逻辑START====================*/ | ||
| 130 | - @Schema(description = "是否为子码流(true-是,false-主码流)") | ||
| 131 | - private boolean subStream; | ||
| 132 | - | ||
| 133 | - public boolean isSubStream() { | ||
| 134 | - return subStream; | ||
| 135 | - } | ||
| 136 | - | ||
| 137 | - public void setSubStream(boolean subStream) { | ||
| 138 | - this.subStream = subStream; | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | - | ||
| 142 | - | ||
| 143 | - | ||
| 144 | } | 127 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
| @@ -452,27 +452,11 @@ public class Device { | @@ -452,27 +452,11 @@ public class Device { | ||
| 452 | public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) { | 452 | public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) { |
| 453 | this.sipTransactionInfo = sipTransactionInfo; | 453 | this.sipTransactionInfo = sipTransactionInfo; |
| 454 | } | 454 | } |
| 455 | + public boolean isBroadcastPushAfterAck() { | ||
| 456 | + return broadcastPushAfterAck; | ||
| 457 | + } | ||
| 455 | 458 | ||
| 456 | - /*======================设备主子码流逻辑START=========================*/ | ||
| 457 | - @Schema(description = "开启主子码流切换的开关(false-不开启,true-开启)") | ||
| 458 | - private boolean switchPrimarySubStream; | ||
| 459 | - | ||
| 460 | - public boolean isSwitchPrimarySubStream() { | ||
| 461 | - return switchPrimarySubStream; | ||
| 462 | - } | ||
| 463 | - | ||
| 464 | - public void setSwitchPrimarySubStream(boolean switchPrimarySubStream) { | ||
| 465 | - this.switchPrimarySubStream = switchPrimarySubStream; | ||
| 466 | - } | ||
| 467 | - | ||
| 468 | - /*======================设备主子码流逻辑END=========================*/ | ||
| 469 | - | ||
| 470 | - | ||
| 471 | - public boolean isBroadcastPushAfterAck() { | ||
| 472 | - return broadcastPushAfterAck; | ||
| 473 | - } | ||
| 474 | - | ||
| 475 | - public void setBroadcastPushAfterAck(boolean broadcastPushAfterAck) { | ||
| 476 | - this.broadcastPushAfterAck = broadcastPushAfterAck; | ||
| 477 | - } | 459 | + public void setBroadcastPushAfterAck(boolean broadcastPushAfterAck) { |
| 460 | + this.broadcastPushAfterAck = broadcastPushAfterAck; | ||
| 461 | + } | ||
| 478 | } | 462 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
| @@ -246,6 +246,10 @@ public class DeviceChannel { | @@ -246,6 +246,10 @@ public class DeviceChannel { | ||
| 246 | @Schema(description = "GPS的更新时间") | 246 | @Schema(description = "GPS的更新时间") |
| 247 | private String gpsTime; | 247 | private String gpsTime; |
| 248 | 248 | ||
| 249 | + @Schema(description = "码流标识,优先级高于设备中码流标识," + | ||
| 250 | + "用于选择码流时组成码流标识。默认为null,不设置。可选值: stream/streamnumber/streamprofile/streamMode") | ||
| 251 | + private String streamIdentification; | ||
| 252 | + | ||
| 249 | public int getId() { | 253 | public int getId() { |
| 250 | return id; | 254 | return id; |
| 251 | } | 255 | } |
| @@ -574,4 +578,12 @@ public class DeviceChannel { | @@ -574,4 +578,12 @@ public class DeviceChannel { | ||
| 574 | public void setGpsTime(String gpsTime) { | 578 | public void setGpsTime(String gpsTime) { |
| 575 | this.gpsTime = gpsTime; | 579 | this.gpsTime = gpsTime; |
| 576 | } | 580 | } |
| 581 | + | ||
| 582 | + public String getStreamIdentification() { | ||
| 583 | + return streamIdentification; | ||
| 584 | + } | ||
| 585 | + | ||
| 586 | + public void setStreamIdentification(String streamIdentification) { | ||
| 587 | + this.streamIdentification = streamIdentification; | ||
| 588 | + } | ||
| 577 | } | 589 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbSteamIdentification.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.gb28181.bean; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 码流索引标识 | ||
| 5 | + */ | ||
| 6 | +public enum GbSteamIdentification { | ||
| 7 | + /** | ||
| 8 | + * 主码流 stream:0 | ||
| 9 | + * 子码流 stream:1s | ||
| 10 | + */ | ||
| 11 | + streamMain("stream", new String[]{"0","1"}), | ||
| 12 | + /** | ||
| 13 | + * 国标28181-2022定义的方式 | ||
| 14 | + * 主码流 streamnumber:0 | ||
| 15 | + * 子码流 streamnumber:1 | ||
| 16 | + */ | ||
| 17 | + streamnumber("streamnumber", new String[]{"0","1"}), | ||
| 18 | + /** | ||
| 19 | + * 主码流 streamprofile:0 | ||
| 20 | + * 子码流 streamprofile:1 | ||
| 21 | + */ | ||
| 22 | + streamprofile("streamprofile", new String[]{"0","1"}), | ||
| 23 | + /** | ||
| 24 | + * 适用的品牌: TP-LINK | ||
| 25 | + */ | ||
| 26 | + streamMode("streamMode", new String[]{"main","sub"}), | ||
| 27 | + ; | ||
| 28 | + | ||
| 29 | + GbSteamIdentification(String value, String[] indexArray) { | ||
| 30 | + this.value = value; | ||
| 31 | + this.indexArray = indexArray; | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + private String value; | ||
| 35 | + private String[] indexArray; | ||
| 36 | + | ||
| 37 | + public String getValue() { | ||
| 38 | + return value; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public String[] getIndexArray() { | ||
| 42 | + return indexArray; | ||
| 43 | + } | ||
| 44 | +} |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
| @@ -52,7 +52,7 @@ public class SubscribeHolder { | @@ -52,7 +52,7 @@ public class SubscribeHolder { | ||
| 52 | Runnable runnable = dynamicTask.get(taskOverdueKey); | 52 | Runnable runnable = dynamicTask.get(taskOverdueKey); |
| 53 | if (runnable instanceof ISubscribeTask) { | 53 | if (runnable instanceof ISubscribeTask) { |
| 54 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; | 54 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; |
| 55 | - subscribeTask.stop(); | 55 | + subscribeTask.stop(null); |
| 56 | } | 56 | } |
| 57 | // 添加任务处理订阅过期 | 57 | // 添加任务处理订阅过期 |
| 58 | dynamicTask.stop(taskOverdueKey); | 58 | dynamicTask.stop(taskOverdueKey); |
| @@ -87,7 +87,7 @@ public class SubscribeHolder { | @@ -87,7 +87,7 @@ public class SubscribeHolder { | ||
| 87 | Runnable runnable = dynamicTask.get(taskOverdueKey); | 87 | Runnable runnable = dynamicTask.get(taskOverdueKey); |
| 88 | if (runnable instanceof ISubscribeTask) { | 88 | if (runnable instanceof ISubscribeTask) { |
| 89 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; | 89 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; |
| 90 | - subscribeTask.stop(); | 90 | + subscribeTask.stop(null); |
| 91 | } | 91 | } |
| 92 | // 添加任务处理订阅过期 | 92 | // 添加任务处理订阅过期 |
| 93 | dynamicTask.stop(taskOverdueKey); | 93 | dynamicTask.stop(taskOverdueKey); |
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
| @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.event; | @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.event; | ||
| 2 | 2 | ||
| 3 | import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent; | 3 | import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent; |
| 4 | import gov.nist.javax.sip.message.SIPRequest; | 4 | import gov.nist.javax.sip.message.SIPRequest; |
| 5 | +import gov.nist.javax.sip.message.SIPResponse; | ||
| 6 | +import org.apache.commons.lang3.ObjectUtils; | ||
| 5 | import org.slf4j.Logger; | 7 | import org.slf4j.Logger; |
| 6 | import org.slf4j.LoggerFactory; | 8 | import org.slf4j.LoggerFactory; |
| 7 | import org.springframework.scheduling.annotation.Scheduled; | 9 | import org.springframework.scheduling.annotation.Scheduled; |
| @@ -11,8 +13,7 @@ import javax.sip.DialogTerminatedEvent; | @@ -11,8 +13,7 @@ import javax.sip.DialogTerminatedEvent; | ||
| 11 | import javax.sip.ResponseEvent; | 13 | import javax.sip.ResponseEvent; |
| 12 | import javax.sip.TimeoutEvent; | 14 | import javax.sip.TimeoutEvent; |
| 13 | import javax.sip.TransactionTerminatedEvent; | 15 | import javax.sip.TransactionTerminatedEvent; |
| 14 | -import javax.sip.header.CallIdHeader; | ||
| 15 | -import javax.sip.message.Response; | 16 | +import javax.sip.header.WarningHeader; |
| 16 | import java.time.Instant; | 17 | import java.time.Instant; |
| 17 | import java.util.Map; | 18 | import java.util.Map; |
| 18 | import java.util.concurrent.ConcurrentHashMap; | 19 | import java.util.concurrent.ConcurrentHashMap; |
| @@ -97,14 +98,27 @@ public class SipSubscribe { | @@ -97,14 +98,27 @@ public class SipSubscribe { | ||
| 97 | this.event = event; | 98 | this.event = event; |
| 98 | if (event instanceof ResponseEvent) { | 99 | if (event instanceof ResponseEvent) { |
| 99 | ResponseEvent responseEvent = (ResponseEvent)event; | 100 | ResponseEvent responseEvent = (ResponseEvent)event; |
| 100 | - Response response = responseEvent.getResponse(); | 101 | + SIPResponse response = (SIPResponse)responseEvent.getResponse(); |
| 101 | this.type = EventResultType.response; | 102 | this.type = EventResultType.response; |
| 102 | if (response != null) { | 103 | if (response != null) { |
| 103 | - this.msg = response.getReasonPhrase(); | 104 | + WarningHeader warningHeader = (WarningHeader)response.getHeader(WarningHeader.NAME); |
| 105 | + if (warningHeader != null && !ObjectUtils.isEmpty(warningHeader.getText())) { | ||
| 106 | + this.msg = ""; | ||
| 107 | + if (warningHeader.getCode() > 0) { | ||
| 108 | + this.msg += warningHeader.getCode() + ":"; | ||
| 109 | + } | ||
| 110 | + if (warningHeader.getAgent() != null) { | ||
| 111 | + this.msg += warningHeader.getCode() + ":"; | ||
| 112 | + } | ||
| 113 | + if (warningHeader.getText() != null) { | ||
| 114 | + this.msg += warningHeader.getText(); | ||
| 115 | + } | ||
| 116 | + }else { | ||
| 117 | + this.msg = response.getReasonPhrase(); | ||
| 118 | + } | ||
| 104 | this.statusCode = response.getStatusCode(); | 119 | this.statusCode = response.getStatusCode(); |
| 120 | + this.callId = response.getCallIdHeader().getCallId(); | ||
| 105 | } | 121 | } |
| 106 | - this.callId = ((CallIdHeader)response.getHeader(CallIdHeader.NAME)).getCallId(); | ||
| 107 | - | ||
| 108 | }else if (event instanceof TimeoutEvent) { | 122 | }else if (event instanceof TimeoutEvent) { |
| 109 | TimeoutEvent timeoutEvent = (TimeoutEvent)event; | 123 | TimeoutEvent timeoutEvent = (TimeoutEvent)event; |
| 110 | this.type = EventResultType.timeout; | 124 | this.type = EventResultType.timeout; |
src/main/java/com/genersoft/iot/vmp/gb28181/session/CommonSessionManager.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.gb28181.session; | ||
| 2 | + | ||
| 3 | +import com.genersoft.iot.vmp.common.CommonCallback; | ||
| 4 | +import org.springframework.scheduling.annotation.Scheduled; | ||
| 5 | +import org.springframework.stereotype.Component; | ||
| 6 | + | ||
| 7 | +import java.util.Calendar; | ||
| 8 | +import java.util.Map; | ||
| 9 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 通用回调管理 | ||
| 13 | + */ | ||
| 14 | +@Component | ||
| 15 | +public class CommonSessionManager { | ||
| 16 | + | ||
| 17 | + public static Map<String, CommonSession> callbackMap = new ConcurrentHashMap<>(); | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 存储回调相关的信息 | ||
| 21 | + */ | ||
| 22 | + class CommonSession{ | ||
| 23 | + public String session; | ||
| 24 | + public long createTime; | ||
| 25 | + public int timeout; | ||
| 26 | + | ||
| 27 | + public CommonCallback<Object> callback; | ||
| 28 | + public CommonCallback<String> timeoutCallback; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 添加回调 | ||
| 33 | + * @param sessionId 唯一标识 | ||
| 34 | + * @param callback 回调 | ||
| 35 | + * @param timeout 超时时间, 单位分钟 | ||
| 36 | + */ | ||
| 37 | + public void add(String sessionId, CommonCallback<Object> callback, CommonCallback<String> timeoutCallback, | ||
| 38 | + Integer timeout) { | ||
| 39 | + CommonSession commonSession = new CommonSession(); | ||
| 40 | + commonSession.session = sessionId; | ||
| 41 | + commonSession.callback = callback; | ||
| 42 | + commonSession.createTime = System.currentTimeMillis(); | ||
| 43 | + if (timeoutCallback != null) { | ||
| 44 | + commonSession.timeoutCallback = timeoutCallback; | ||
| 45 | + } | ||
| 46 | + if (timeout != null) { | ||
| 47 | + commonSession.timeout = timeout; | ||
| 48 | + } | ||
| 49 | + callbackMap.put(sessionId, commonSession); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + public void add(String sessionId, CommonCallback<Object> callback) { | ||
| 53 | + add(sessionId, callback, null, 1); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + public CommonCallback<Object> get(String sessionId, boolean destroy) { | ||
| 57 | + CommonSession commonSession = callbackMap.get(sessionId); | ||
| 58 | + if (destroy) { | ||
| 59 | + callbackMap.remove(sessionId); | ||
| 60 | + } | ||
| 61 | + return commonSession.callback; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + public CommonCallback<Object> get(String sessionId) { | ||
| 65 | + return get(sessionId, false); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + public void delete(String sessionID) { | ||
| 69 | + callbackMap.remove(sessionID); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Scheduled(fixedRate= 60) //每分钟执行一次 | ||
| 73 | + public void execute(){ | ||
| 74 | + Calendar cal = Calendar.getInstance(); | ||
| 75 | + cal.add(Calendar.MINUTE, -1); | ||
| 76 | + for (String session : callbackMap.keySet()) { | ||
| 77 | + if (callbackMap.get(session).createTime < cal.getTimeInMillis()) { | ||
| 78 | + // 超时 | ||
| 79 | + if (callbackMap.get(session).timeoutCallback != null) { | ||
| 80 | + callbackMap.get(session).timeoutCallback.run("timeout"); | ||
| 81 | + } | ||
| 82 | + callbackMap.remove(session); | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | +} |
src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
| 1 | package com.genersoft.iot.vmp.gb28181.task; | 1 | package com.genersoft.iot.vmp.gb28181.task; |
| 2 | 2 | ||
| 3 | -import javax.sip.DialogState; | 3 | +import com.genersoft.iot.vmp.common.CommonCallback; |
| 4 | 4 | ||
| 5 | /** | 5 | /** |
| 6 | * @author lin | 6 | * @author lin |
| 7 | */ | 7 | */ |
| 8 | public interface ISubscribeTask extends Runnable{ | 8 | public interface ISubscribeTask extends Runnable{ |
| 9 | - void stop(); | 9 | + void stop(CommonCallback<Boolean> callback); |
| 10 | } | 10 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
| 1 | package com.genersoft.iot.vmp.gb28181.task.impl; | 1 | package com.genersoft.iot.vmp.gb28181.task.impl; |
| 2 | 2 | ||
| 3 | +import com.genersoft.iot.vmp.common.CommonCallback; | ||
| 3 | import com.genersoft.iot.vmp.conf.DynamicTask; | 4 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; | 6 | import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; |
| @@ -7,14 +8,13 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; | @@ -7,14 +8,13 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; | ||
| 7 | import gov.nist.javax.sip.message.SIPRequest; | 8 | import gov.nist.javax.sip.message.SIPRequest; |
| 8 | import org.slf4j.Logger; | 9 | import org.slf4j.Logger; |
| 9 | import org.slf4j.LoggerFactory; | 10 | import org.slf4j.LoggerFactory; |
| 10 | -import org.springframework.scheduling.annotation.Async; | ||
| 11 | -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||
| 12 | 11 | ||
| 13 | -import javax.sip.*; | 12 | +import javax.sip.DialogState; |
| 13 | +import javax.sip.InvalidArgumentException; | ||
| 14 | +import javax.sip.ResponseEvent; | ||
| 15 | +import javax.sip.SipException; | ||
| 14 | import javax.sip.header.ToHeader; | 16 | import javax.sip.header.ToHeader; |
| 15 | import java.text.ParseException; | 17 | import java.text.ParseException; |
| 16 | -import java.util.Timer; | ||
| 17 | -import java.util.TimerTask; | ||
| 18 | 18 | ||
| 19 | /** | 19 | /** |
| 20 | * 目录订阅任务 | 20 | * 目录订阅任务 |
| @@ -71,7 +71,7 @@ public class CatalogSubscribeTask implements ISubscribeTask { | @@ -71,7 +71,7 @@ public class CatalogSubscribeTask implements ISubscribeTask { | ||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | @Override | 73 | @Override |
| 74 | - public void stop() { | 74 | + public void stop(CommonCallback<Boolean> callback) { |
| 75 | /** | 75 | /** |
| 76 | * dialog 的各个状态 | 76 | * dialog 的各个状态 |
| 77 | * EARLY-> Early state状态-初始请求发送以后,收到了一个临时响应消息 | 77 | * EARLY-> Early state状态-初始请求发送以后,收到了一个临时响应消息 |
| @@ -94,6 +94,9 @@ public class CatalogSubscribeTask implements ISubscribeTask { | @@ -94,6 +94,9 @@ public class CatalogSubscribeTask implements ISubscribeTask { | ||
| 94 | // 成功 | 94 | // 成功 |
| 95 | logger.info("[取消目录订阅]成功: {}", device.getDeviceId()); | 95 | logger.info("[取消目录订阅]成功: {}", device.getDeviceId()); |
| 96 | } | 96 | } |
| 97 | + if (callback != null) { | ||
| 98 | + callback.run(event.getResponse().getRawContent() != null); | ||
| 99 | + } | ||
| 97 | },eventResult -> { | 100 | },eventResult -> { |
| 98 | // 失败 | 101 | // 失败 |
| 99 | logger.warn("[取消目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); | 102 | logger.warn("[取消目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); |
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
| 1 | package com.genersoft.iot.vmp.gb28181.task.impl; | 1 | package com.genersoft.iot.vmp.gb28181.task.impl; |
| 2 | 2 | ||
| 3 | -import com.genersoft.iot.vmp.conf.DynamicTask; | ||
| 4 | -import com.genersoft.iot.vmp.gb28181.bean.*; | 3 | +import com.genersoft.iot.vmp.common.CommonCallback; |
| 5 | import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; | 4 | import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; |
| 6 | -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; | ||
| 7 | import com.genersoft.iot.vmp.service.IPlatformService; | 5 | import com.genersoft.iot.vmp.service.IPlatformService; |
| 8 | -import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; | ||
| 9 | -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 10 | -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | ||
| 11 | import com.genersoft.iot.vmp.utils.SpringBeanFactory; | 6 | import com.genersoft.iot.vmp.utils.SpringBeanFactory; |
| 12 | -import org.slf4j.Logger; | ||
| 13 | -import org.slf4j.LoggerFactory; | ||
| 14 | -import org.springframework.scheduling.annotation.Async; | ||
| 15 | - | ||
| 16 | -import javax.sip.DialogState; | ||
| 17 | -import java.util.List; | ||
| 18 | 7 | ||
| 19 | /** | 8 | /** |
| 20 | * 向已经订阅(移动位置)的上级发送MobilePosition消息 | 9 | * 向已经订阅(移动位置)的上级发送MobilePosition消息 |
| @@ -38,7 +27,7 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask { | @@ -38,7 +27,7 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask { | ||
| 38 | } | 27 | } |
| 39 | 28 | ||
| 40 | @Override | 29 | @Override |
| 41 | - public void stop() { | 30 | + public void stop(CommonCallback<Boolean> callback) { |
| 42 | 31 | ||
| 43 | } | 32 | } |
| 44 | } | 33 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
| 1 | package com.genersoft.iot.vmp.gb28181.task.impl; | 1 | package com.genersoft.iot.vmp.gb28181.task.impl; |
| 2 | 2 | ||
| 3 | +import com.genersoft.iot.vmp.common.CommonCallback; | ||
| 3 | import com.genersoft.iot.vmp.conf.DynamicTask; | 4 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; | 6 | import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; |
| 6 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; | 7 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 7 | import gov.nist.javax.sip.message.SIPRequest; | 8 | import gov.nist.javax.sip.message.SIPRequest; |
| 8 | -import gov.nist.javax.sip.message.SIPResponse; | ||
| 9 | -import org.dom4j.Element; | ||
| 10 | import org.slf4j.Logger; | 9 | import org.slf4j.Logger; |
| 11 | import org.slf4j.LoggerFactory; | 10 | import org.slf4j.LoggerFactory; |
| 12 | -import org.springframework.scheduling.annotation.Async; | ||
| 13 | 11 | ||
| 14 | -import javax.sip.*; | 12 | +import javax.sip.InvalidArgumentException; |
| 13 | +import javax.sip.ResponseEvent; | ||
| 14 | +import javax.sip.SipException; | ||
| 15 | import javax.sip.header.ToHeader; | 15 | import javax.sip.header.ToHeader; |
| 16 | import java.text.ParseException; | 16 | import java.text.ParseException; |
| 17 | -import java.util.Timer; | ||
| 18 | -import java.util.TimerTask; | ||
| 19 | 17 | ||
| 20 | /** | 18 | /** |
| 21 | * 移动位置订阅的定时更新 | 19 | * 移动位置订阅的定时更新 |
| @@ -70,7 +68,7 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { | @@ -70,7 +68,7 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { | ||
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | @Override | 70 | @Override |
| 73 | - public void stop() { | 71 | + public void stop(CommonCallback<Boolean> callback) { |
| 74 | /** | 72 | /** |
| 75 | * dialog 的各个状态 | 73 | * dialog 的各个状态 |
| 76 | * EARLY-> Early state状态-初始请求发送以后,收到了一个临时响应消息 | 74 | * EARLY-> Early state状态-初始请求发送以后,收到了一个临时响应消息 |
| @@ -92,6 +90,9 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { | @@ -92,6 +90,9 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { | ||
| 92 | // 成功 | 90 | // 成功 |
| 93 | logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); | 91 | logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); |
| 94 | } | 92 | } |
| 93 | + if (callback != null) { | ||
| 94 | + callback.run(event.getResponse().getRawContent() != null); | ||
| 95 | + } | ||
| 95 | },eventResult -> { | 96 | },eventResult -> { |
| 96 | // 失败 | 97 | // 失败 |
| 97 | logger.warn("[取消移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); | 98 | logger.warn("[取消移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
| @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | ||
| 5 | import com.genersoft.iot.vmp.gb28181.bean.*; | 5 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 6 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 6 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 7 | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | 7 | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; |
| 8 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | ||
| 8 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | 9 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 9 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | 10 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| 10 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 11 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| @@ -97,9 +98,9 @@ public interface ISIPCommander { | @@ -97,9 +98,9 @@ public interface ISIPCommander { | ||
| 97 | /** | 98 | /** |
| 98 | * 请求预览视频流 | 99 | * 请求预览视频流 |
| 99 | * @param device 视频设备 | 100 | * @param device 视频设备 |
| 100 | - * @param channelId 预览通道 | 101 | + * @param channel 预览通道 |
| 101 | */ | 102 | */ |
| 102 | - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; | 103 | + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; |
| 103 | 104 | ||
| 104 | /** | 105 | /** |
| 105 | * 请求回放视频流 | 106 | * 请求回放视频流 |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| @@ -7,6 +7,10 @@ import com.genersoft.iot.vmp.conf.UserSetting; | @@ -7,6 +7,10 @@ import com.genersoft.iot.vmp.conf.UserSetting; | ||
| 7 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | 7 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; |
| 8 | import com.genersoft.iot.vmp.gb28181.SipLayer; | 8 | import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 9 | import com.genersoft.iot.vmp.gb28181.bean.*; | 9 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 10 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | ||
| 11 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | ||
| 12 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | ||
| 13 | +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; | ||
| 10 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | 14 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 11 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | 15 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 12 | import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; | 16 | import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; |
| @@ -266,12 +270,12 @@ public class SIPCommander implements ISIPCommander { | @@ -266,12 +270,12 @@ public class SIPCommander implements ISIPCommander { | ||
| 266 | * 请求预览视频流 | 270 | * 请求预览视频流 |
| 267 | * | 271 | * |
| 268 | * @param device 视频设备 | 272 | * @param device 视频设备 |
| 269 | - * @param channelId 预览通道 | 273 | + * @param channel 预览通道 |
| 270 | * @param event hook订阅 | 274 | * @param event hook订阅 |
| 271 | * @param errorEvent sip错误订阅 | 275 | * @param errorEvent sip错误订阅 |
| 272 | */ | 276 | */ |
| 273 | @Override | 277 | @Override |
| 274 | - public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | 278 | + public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel, |
| 275 | ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { | 279 | ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { |
| 276 | String stream = ssrcInfo.getStream(); | 280 | String stream = ssrcInfo.getStream(); |
| 277 | 281 | ||
| @@ -295,7 +299,7 @@ public class SIPCommander implements ISIPCommander { | @@ -295,7 +299,7 @@ public class SIPCommander implements ISIPCommander { | ||
| 295 | } | 299 | } |
| 296 | StringBuffer content = new StringBuffer(200); | 300 | StringBuffer content = new StringBuffer(200); |
| 297 | content.append("v=0\r\n"); | 301 | content.append("v=0\r\n"); |
| 298 | - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n"); | 302 | + content.append("o=" + channel.getChannelId() + " 0 0 IN IP4 " + sdpIp + "\r\n"); |
| 299 | content.append("s=Play\r\n"); | 303 | content.append("s=Play\r\n"); |
| 300 | content.append("c=IN IP4 " + sdpIp + "\r\n"); | 304 | content.append("c=IN IP4 " + sdpIp + "\r\n"); |
| 301 | content.append("t=0 0\r\n"); | 305 | content.append("t=0 0\r\n"); |
| @@ -346,20 +350,8 @@ public class SIPCommander implements ISIPCommander { | @@ -346,20 +350,8 @@ public class SIPCommander implements ISIPCommander { | ||
| 346 | } | 350 | } |
| 347 | } | 351 | } |
| 348 | 352 | ||
| 349 | - if( device.isSwitchPrimarySubStream() ){ | ||
| 350 | - if("TP-LINK".equals(device.getManufacturer())){ | ||
| 351 | - if (device.isSwitchPrimarySubStream()){ | ||
| 352 | - content.append("a=streamMode:sub\r\n"); | ||
| 353 | - }else { | ||
| 354 | - content.append("a=streamMode:main\r\n"); | ||
| 355 | - } | ||
| 356 | - }else { | ||
| 357 | - if (device.isSwitchPrimarySubStream()){ | ||
| 358 | - content.append("a=streamprofile:1\r\n"); | ||
| 359 | - }else { | ||
| 360 | - content.append("a=streamprofile:0\r\n"); | ||
| 361 | - } | ||
| 362 | - } | 353 | + if (!ObjectUtils.isEmpty(channel.getStreamIdentification())) { |
| 354 | + content.append("a=" + channel.getStreamIdentification() + "\r\n"); | ||
| 363 | } | 355 | } |
| 364 | 356 | ||
| 365 | content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc | 357 | content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc |
| @@ -368,16 +360,16 @@ public class SIPCommander implements ISIPCommander { | @@ -368,16 +360,16 @@ public class SIPCommander implements ISIPCommander { | ||
| 368 | 360 | ||
| 369 | 361 | ||
| 370 | 362 | ||
| 371 | - Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); | 363 | + Request request = headerProvider.createInviteRequest(device, channel.getChannelId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); |
| 372 | sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> { | 364 | sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> { |
| 373 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | 365 | + streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream()); |
| 374 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | 366 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| 375 | errorEvent.response(e); | 367 | errorEvent.response(e); |
| 376 | }), e -> { | 368 | }), e -> { |
| 377 | ResponseEvent responseEvent = (ResponseEvent) e.event; | 369 | ResponseEvent responseEvent = (ResponseEvent) e.event; |
| 378 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); | 370 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); |
| 379 | String callId = response.getCallIdHeader().getCallId(); | 371 | String callId = response.getCallIdHeader().getCallId(); |
| 380 | - streamSession.put(device.getDeviceId(), channelId, callId, stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, | 372 | + streamSession.put(device.getDeviceId(), channel.getChannelId(), callId, stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, |
| 381 | InviteSessionType.PLAY); | 373 | InviteSessionType.PLAY); |
| 382 | okEvent.response(e); | 374 | okEvent.response(e); |
| 383 | }); | 375 | }); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
| @@ -6,7 +6,6 @@ import com.genersoft.iot.vmp.conf.SipConfig; | @@ -6,7 +6,6 @@ import com.genersoft.iot.vmp.conf.SipConfig; | ||
| 6 | import com.genersoft.iot.vmp.conf.UserSetting; | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 7 | import com.genersoft.iot.vmp.gb28181.bean.*; | 7 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 8 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | 8 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 9 | -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; | ||
| 10 | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; | 9 | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| 11 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | 10 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 12 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | 11 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| @@ -38,7 +37,6 @@ import javax.sip.SipException; | @@ -38,7 +37,6 @@ import javax.sip.SipException; | ||
| 38 | import javax.sip.header.FromHeader; | 37 | import javax.sip.header.FromHeader; |
| 39 | import javax.sip.message.Response; | 38 | import javax.sip.message.Response; |
| 40 | import java.text.ParseException; | 39 | import java.text.ParseException; |
| 41 | -import java.util.Iterator; | ||
| 42 | import java.util.List; | 40 | import java.util.List; |
| 43 | import java.util.concurrent.ConcurrentLinkedQueue; | 41 | import java.util.concurrent.ConcurrentLinkedQueue; |
| 44 | 42 | ||
| @@ -222,7 +220,6 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements | @@ -222,7 +220,6 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements | ||
| 222 | mobilePosition.getLongitude(), mobilePosition.getLatitude()); | 220 | mobilePosition.getLongitude(), mobilePosition.getLatitude()); |
| 223 | mobilePosition.setReportSource("Mobile Position"); | 221 | mobilePosition.setReportSource("Mobile Position"); |
| 224 | 222 | ||
| 225 | - | ||
| 226 | // 更新device channel 的经纬度 | 223 | // 更新device channel 的经纬度 |
| 227 | DeviceChannel deviceChannel = new DeviceChannel(); | 224 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 228 | deviceChannel.setDeviceId(device.getDeviceId()); | 225 | deviceChannel.setDeviceId(device.getDeviceId()); |
| @@ -242,6 +239,8 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements | @@ -242,6 +239,8 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements | ||
| 242 | } | 239 | } |
| 243 | 240 | ||
| 244 | storager.updateChannelPosition(deviceChannel); | 241 | storager.updateChannelPosition(deviceChannel); |
| 242 | + // 向关联了该通道并且开启移动位置订阅的上级平台发送移动位置订阅消息 | ||
| 243 | + | ||
| 245 | 244 | ||
| 246 | // 发送redis消息。 通知位置信息的变化 | 245 | // 发送redis消息。 通知位置信息的变化 |
| 247 | JSONObject jsonObject = new JSONObject(); | 246 | JSONObject jsonObject = new JSONObject(); |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
| @@ -82,8 +82,9 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp | @@ -82,8 +82,9 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp | ||
| 82 | device.setIp(remoteAddressInfo.getIp()); | 82 | device.setIp(remoteAddressInfo.getIp()); |
| 83 | // 设备地址变化会引起目录订阅任务失效,需要重新添加 | 83 | // 设备地址变化会引起目录订阅任务失效,需要重新添加 |
| 84 | if (device.getSubscribeCycleForCatalog() > 0) { | 84 | if (device.getSubscribeCycleForCatalog() > 0) { |
| 85 | - deviceService.removeCatalogSubscribe(device); | ||
| 86 | - deviceService.addCatalogSubscribe(device); | 85 | + deviceService.removeCatalogSubscribe(device, result->{ |
| 86 | + deviceService.addCatalogSubscribe(device); | ||
| 87 | + }); | ||
| 87 | } | 88 | } |
| 88 | } | 89 | } |
| 89 | if (device.getKeepaliveTime() == null) { | 90 | if (device.getKeepaliveTime() == null) { |
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
| @@ -87,4 +87,9 @@ public interface IDeviceChannelService { | @@ -87,4 +87,9 @@ public interface IDeviceChannelService { | ||
| 87 | * 直接批量添加 | 87 | * 直接批量添加 |
| 88 | */ | 88 | */ |
| 89 | void batchAddChannel(List<DeviceChannel> deviceChannels); | 89 | void batchAddChannel(List<DeviceChannel> deviceChannels); |
| 90 | + | ||
| 91 | + /** | ||
| 92 | + * 修改通道的码流类型 | ||
| 93 | + */ | ||
| 94 | + void updateChannelStreamIdentification(DeviceChannel channel); | ||
| 90 | } | 95 | } |
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
| 1 | package com.genersoft.iot.vmp.service; | 1 | package com.genersoft.iot.vmp.service; |
| 2 | 2 | ||
| 3 | +import com.genersoft.iot.vmp.common.CommonCallback; | ||
| 3 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 4 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 5 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 5 | import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; | 6 | import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; |
| @@ -39,7 +40,7 @@ public interface IDeviceService { | @@ -39,7 +40,7 @@ public interface IDeviceService { | ||
| 39 | * @param device 设备信息 | 40 | * @param device 设备信息 |
| 40 | * @return 布尔 | 41 | * @return 布尔 |
| 41 | */ | 42 | */ |
| 42 | - boolean removeCatalogSubscribe(Device device); | 43 | + boolean removeCatalogSubscribe(Device device, CommonCallback<Boolean> callback); |
| 43 | 44 | ||
| 44 | /** | 45 | /** |
| 45 | * 添加移动位置订阅 | 46 | * 添加移动位置订阅 |
| @@ -53,7 +54,7 @@ public interface IDeviceService { | @@ -53,7 +54,7 @@ public interface IDeviceService { | ||
| 53 | * @param device 设备信息 | 54 | * @param device 设备信息 |
| 54 | * @return 布尔 | 55 | * @return 布尔 |
| 55 | */ | 56 | */ |
| 56 | - boolean removeMobilePositionSubscribe(Device device); | 57 | + boolean removeMobilePositionSubscribe(Device device, CommonCallback<Boolean> callback); |
| 57 | 58 | ||
| 58 | /** | 59 | /** |
| 59 | * 移除移动位置订阅 | 60 | * 移除移动位置订阅 |
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
| @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.conf.exception.ServiceException; | @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.conf.exception.ServiceException; | ||
| 6 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 6 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 7 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | 7 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 8 | import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; | 8 | import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; |
| 9 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | ||
| 9 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 10 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 10 | import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | 11 | import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; |
| 11 | import com.genersoft.iot.vmp.service.bean.ErrorCallback; | 12 | import com.genersoft.iot.vmp.service.bean.ErrorCallback; |
| @@ -25,7 +26,7 @@ import java.util.Map; | @@ -25,7 +26,7 @@ import java.util.Map; | ||
| 25 | */ | 26 | */ |
| 26 | public interface IPlayService { | 27 | public interface IPlayService { |
| 27 | 28 | ||
| 28 | - void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | 29 | + void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channelId, |
| 29 | ErrorCallback<Object> callback); | 30 | ErrorCallback<Object> callback); |
| 30 | SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback); | 31 | SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback); |
| 31 | 32 |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
| @@ -18,6 +18,7 @@ import org.slf4j.Logger; | @@ -18,6 +18,7 @@ import org.slf4j.Logger; | ||
| 18 | import org.slf4j.LoggerFactory; | 18 | import org.slf4j.LoggerFactory; |
| 19 | import org.springframework.beans.factory.annotation.Autowired; | 19 | import org.springframework.beans.factory.annotation.Autowired; |
| 20 | import org.springframework.stereotype.Service; | 20 | import org.springframework.stereotype.Service; |
| 21 | +import org.springframework.util.ObjectUtils; | ||
| 21 | 22 | ||
| 22 | import java.util.ArrayList; | 23 | import java.util.ArrayList; |
| 23 | import java.util.HashMap; | 24 | import java.util.HashMap; |
| @@ -267,5 +268,16 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { | @@ -267,5 +268,16 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { | ||
| 267 | } | 268 | } |
| 268 | } | 269 | } |
| 269 | 270 | ||
| 270 | - | 271 | + @Override |
| 272 | + public void updateChannelStreamIdentification(DeviceChannel channel) { | ||
| 273 | + assert !ObjectUtils.isEmpty(channel.getDeviceId()); | ||
| 274 | + assert !ObjectUtils.isEmpty(channel.getStreamIdentification()); | ||
| 275 | + if (ObjectUtils.isEmpty(channel.getStreamIdentification())) { | ||
| 276 | + logger.info("[重置通道码流类型] 设备: {}, 码流: {}", channel.getDeviceId(), channel.getStreamIdentification()); | ||
| 277 | + }else { | ||
| 278 | + logger.info("[更新通道码流类型] 设备: {}, 通道:{}, 码流: {}", channel.getDeviceId(), channel.getChannelId(), | ||
| 279 | + channel.getStreamIdentification()); | ||
| 280 | + } | ||
| 281 | + channelMapper.updateChannelStreamIdentification(channel); | ||
| 282 | + } | ||
| 271 | } | 283 | } |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
| 1 | package com.genersoft.iot.vmp.service.impl; | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | ||
| 3 | import com.baomidou.dynamic.datasource.annotation.DS; | 3 | import com.baomidou.dynamic.datasource.annotation.DS; |
| 4 | +import com.genersoft.iot.vmp.common.CommonCallback; | ||
| 4 | import com.genersoft.iot.vmp.common.VideoManagerConstants; | 5 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 5 | import com.genersoft.iot.vmp.conf.DynamicTask; | 6 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 6 | import com.genersoft.iot.vmp.conf.UserSetting; | 7 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 7 | -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | ||
| 8 | import com.genersoft.iot.vmp.gb28181.bean.*; | 8 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 9 | import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; | 9 | import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; |
| 10 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | 10 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| @@ -145,10 +145,6 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -145,10 +145,6 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 145 | } | 145 | } |
| 146 | sync(device); | 146 | sync(device); |
| 147 | }else { | 147 | }else { |
| 148 | - | ||
| 149 | - if (deviceInDb != null) { | ||
| 150 | - device.setSwitchPrimarySubStream(deviceInDb.isSwitchPrimarySubStream()); | ||
| 151 | - } | ||
| 152 | if(!device.isOnLine()){ | 148 | if(!device.isOnLine()){ |
| 153 | device.setOnLine(true); | 149 | device.setOnLine(true); |
| 154 | device.setCreateTime(now); | 150 | device.setCreateTime(now); |
| @@ -238,12 +234,8 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -238,12 +234,8 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 238 | } | 234 | } |
| 239 | } | 235 | } |
| 240 | // 移除订阅 | 236 | // 移除订阅 |
| 241 | - removeCatalogSubscribe(device); | ||
| 242 | - removeMobilePositionSubscribe(device); | ||
| 243 | - if (userSetting.getDeviceStatusNotify()) { | ||
| 244 | - // 发送redis消息 | ||
| 245 | - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, false); | ||
| 246 | - } | 237 | + removeCatalogSubscribe(device, null); |
| 238 | + removeMobilePositionSubscribe(device, null); | ||
| 247 | 239 | ||
| 248 | List<AudioBroadcastCatch> audioBroadcastCatches = audioBroadcastManager.get(deviceId); | 240 | List<AudioBroadcastCatch> audioBroadcastCatches = audioBroadcastManager.get(deviceId); |
| 249 | if (audioBroadcastCatches.size() > 0) { | 241 | if (audioBroadcastCatches.size() > 0) { |
| @@ -281,7 +273,7 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -281,7 +273,7 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 281 | } | 273 | } |
| 282 | 274 | ||
| 283 | @Override | 275 | @Override |
| 284 | - public boolean removeCatalogSubscribe(Device device) { | 276 | + public boolean removeCatalogSubscribe(Device device, CommonCallback<Boolean> callback) { |
| 285 | if (device == null || device.getSubscribeCycleForCatalog() < 0) { | 277 | if (device == null || device.getSubscribeCycleForCatalog() < 0) { |
| 286 | return false; | 278 | return false; |
| 287 | } | 279 | } |
| @@ -291,7 +283,7 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -291,7 +283,7 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 291 | Runnable runnable = dynamicTask.get(taskKey); | 283 | Runnable runnable = dynamicTask.get(taskKey); |
| 292 | if (runnable instanceof ISubscribeTask) { | 284 | if (runnable instanceof ISubscribeTask) { |
| 293 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; | 285 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; |
| 294 | - subscribeTask.stop(); | 286 | + subscribeTask.stop(callback); |
| 295 | } | 287 | } |
| 296 | } | 288 | } |
| 297 | dynamicTask.stop(taskKey); | 289 | dynamicTask.stop(taskKey); |
| @@ -314,7 +306,7 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -314,7 +306,7 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 314 | } | 306 | } |
| 315 | 307 | ||
| 316 | @Override | 308 | @Override |
| 317 | - public boolean removeMobilePositionSubscribe(Device device) { | 309 | + public boolean removeMobilePositionSubscribe(Device device, CommonCallback<Boolean> callback) { |
| 318 | if (device == null || device.getSubscribeCycleForCatalog() < 0) { | 310 | if (device == null || device.getSubscribeCycleForCatalog() < 0) { |
| 319 | return false; | 311 | return false; |
| 320 | } | 312 | } |
| @@ -324,7 +316,7 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -324,7 +316,7 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 324 | Runnable runnable = dynamicTask.get(taskKey); | 316 | Runnable runnable = dynamicTask.get(taskKey); |
| 325 | if (runnable instanceof ISubscribeTask) { | 317 | if (runnable instanceof ISubscribeTask) { |
| 326 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; | 318 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; |
| 327 | - subscribeTask.stop(); | 319 | + subscribeTask.stop(callback); |
| 328 | } | 320 | } |
| 329 | } | 321 | } |
| 330 | dynamicTask.stop(taskKey); | 322 | dynamicTask.stop(taskKey); |
| @@ -515,21 +507,6 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -515,21 +507,6 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 515 | logger.warn("更新设备时未找到设备信息"); | 507 | logger.warn("更新设备时未找到设备信息"); |
| 516 | return; | 508 | return; |
| 517 | } | 509 | } |
| 518 | - if(deviceInStore.isSwitchPrimarySubStream() != device.isSwitchPrimarySubStream()){ | ||
| 519 | - //当修改设备的主子码流开关时,需要校验是否存在流,如果存在流则直接关闭 | ||
| 520 | - List<SsrcTransaction> ssrcTransactionForAll = streamSession.getSsrcTransactionForAll(device.getDeviceId(), null, null, null); | ||
| 521 | - if(ssrcTransactionForAll != null){ | ||
| 522 | - for (SsrcTransaction ssrcTransaction: ssrcTransactionForAll) { | ||
| 523 | - try { | ||
| 524 | - cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), ssrcTransaction.getStream(), null, null); | ||
| 525 | - } catch (InvalidArgumentException | SsrcTransactionNotFoundException | ParseException | SipException e) { | ||
| 526 | - throw new RuntimeException(e); | ||
| 527 | - } | ||
| 528 | - } | ||
| 529 | - } | ||
| 530 | - deviceChannelMapper.clearPlay(device.getDeviceId()); | ||
| 531 | - inviteStreamService.clearInviteInfo(device.getDeviceId()); | ||
| 532 | - } | ||
| 533 | 510 | ||
| 534 | if (!ObjectUtils.isEmpty(device.getName())) { | 511 | if (!ObjectUtils.isEmpty(device.getName())) { |
| 535 | deviceInStore.setName(device.getName()); | 512 | deviceInStore.setName(device.getName()); |
| @@ -552,39 +529,54 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -552,39 +529,54 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 552 | if (!ObjectUtils.isEmpty(device.getStreamMode())) { | 529 | if (!ObjectUtils.isEmpty(device.getStreamMode())) { |
| 553 | deviceInStore.setStreamMode(device.getStreamMode()); | 530 | deviceInStore.setStreamMode(device.getStreamMode()); |
| 554 | } | 531 | } |
| 555 | - | ||
| 556 | - | ||
| 557 | // 目录订阅相关的信息 | 532 | // 目录订阅相关的信息 |
| 558 | if (deviceInStore.getSubscribeCycleForCatalog() != device.getSubscribeCycleForCatalog()) { | 533 | if (deviceInStore.getSubscribeCycleForCatalog() != device.getSubscribeCycleForCatalog()) { |
| 559 | if (device.getSubscribeCycleForCatalog() > 0) { | 534 | if (device.getSubscribeCycleForCatalog() > 0) { |
| 560 | // 若已开启订阅,但订阅周期不同,则先取消 | 535 | // 若已开启订阅,但订阅周期不同,则先取消 |
| 561 | if (deviceInStore.getSubscribeCycleForCatalog() != 0) { | 536 | if (deviceInStore.getSubscribeCycleForCatalog() != 0) { |
| 562 | - removeCatalogSubscribe(deviceInStore); | 537 | + removeCatalogSubscribe(deviceInStore, result->{ |
| 538 | + // 开启订阅 | ||
| 539 | + deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog()); | ||
| 540 | + addCatalogSubscribe(deviceInStore); | ||
| 541 | + // 因为是异步执行,需要在这里更新下数据 | ||
| 542 | + deviceMapper.updateCustom(deviceInStore); | ||
| 543 | + redisCatchStorage.updateDevice(deviceInStore); | ||
| 544 | + }); | ||
| 545 | + }else { | ||
| 546 | + // 开启订阅 | ||
| 547 | + deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog()); | ||
| 548 | + addCatalogSubscribe(deviceInStore); | ||
| 563 | } | 549 | } |
| 564 | - // 开启订阅 | ||
| 565 | - deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog()); | ||
| 566 | - addCatalogSubscribe(deviceInStore); | 550 | + |
| 567 | }else if (device.getSubscribeCycleForCatalog() == 0) { | 551 | }else if (device.getSubscribeCycleForCatalog() == 0) { |
| 568 | // 取消订阅 | 552 | // 取消订阅 |
| 569 | - deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog()); | ||
| 570 | - removeCatalogSubscribe(deviceInStore); | 553 | + deviceInStore.setSubscribeCycleForCatalog(0); |
| 554 | + removeCatalogSubscribe(deviceInStore, null); | ||
| 571 | } | 555 | } |
| 572 | } | 556 | } |
| 573 | - | ||
| 574 | // 移动位置订阅相关的信息 | 557 | // 移动位置订阅相关的信息 |
| 575 | - if (device.getSubscribeCycleForMobilePosition() > 0) { | ||
| 576 | - if (deviceInStore.getSubscribeCycleForMobilePosition() == 0 || deviceInStore.getSubscribeCycleForMobilePosition() != device.getSubscribeCycleForMobilePosition()) { | ||
| 577 | - deviceInStore.setMobilePositionSubmissionInterval(device.getMobilePositionSubmissionInterval()); | ||
| 578 | - deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition()); | ||
| 579 | - // 开启订阅 | ||
| 580 | - addMobilePositionSubscribe(deviceInStore); | ||
| 581 | - } | ||
| 582 | - }else if (device.getSubscribeCycleForMobilePosition() == 0) { | ||
| 583 | - if (deviceInStore.getSubscribeCycleForMobilePosition() != 0) { | ||
| 584 | - deviceInStore.setMobilePositionSubmissionInterval(device.getMobilePositionSubmissionInterval()); | ||
| 585 | - deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition()); | 558 | + if (deviceInStore.getSubscribeCycleForMobilePosition() != device.getSubscribeCycleForMobilePosition()) { |
| 559 | + if (device.getSubscribeCycleForMobilePosition() > 0) { | ||
| 560 | + // 若已开启订阅,但订阅周期不同,则先取消 | ||
| 561 | + if (deviceInStore.getSubscribeCycleForMobilePosition() != 0) { | ||
| 562 | + removeMobilePositionSubscribe(deviceInStore, result->{ | ||
| 563 | + // 开启订阅 | ||
| 564 | + deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition()); | ||
| 565 | + addMobilePositionSubscribe(deviceInStore); | ||
| 566 | + // 因为是异步执行,需要在这里更新下数据 | ||
| 567 | + deviceMapper.updateCustom(deviceInStore); | ||
| 568 | + redisCatchStorage.updateDevice(deviceInStore); | ||
| 569 | + }); | ||
| 570 | + }else { | ||
| 571 | + // 开启订阅 | ||
| 572 | + deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition()); | ||
| 573 | + addMobilePositionSubscribe(deviceInStore); | ||
| 574 | + } | ||
| 575 | + | ||
| 576 | + }else if (device.getSubscribeCycleForMobilePosition() == 0) { | ||
| 586 | // 取消订阅 | 577 | // 取消订阅 |
| 587 | - removeMobilePositionSubscribe(deviceInStore); | 578 | + deviceInStore.setSubscribeCycleForCatalog(0); |
| 579 | + removeCatalogSubscribe(deviceInStore, null); | ||
| 588 | } | 580 | } |
| 589 | } | 581 | } |
| 590 | if (deviceInStore.getGeoCoordSys() != null) { | 582 | if (deviceInStore.getGeoCoordSys() != null) { |
| @@ -603,10 +595,9 @@ public class DeviceServiceImpl implements IDeviceService { | @@ -603,10 +595,9 @@ public class DeviceServiceImpl implements IDeviceService { | ||
| 603 | deviceInStore.setSsrcCheck(device.isSsrcCheck()); | 595 | deviceInStore.setSsrcCheck(device.isSsrcCheck()); |
| 604 | //作为消息通道 | 596 | //作为消息通道 |
| 605 | deviceInStore.setAsMessageChannel(device.isAsMessageChannel()); | 597 | deviceInStore.setAsMessageChannel(device.isAsMessageChannel()); |
| 606 | - | ||
| 607 | - // 更新redis | 598 | + |
| 608 | deviceMapper.updateCustom(deviceInStore); | 599 | deviceMapper.updateCustom(deviceInStore); |
| 609 | - redisCatchStorage.removeDevice(deviceInStore.getDeviceId()); | 600 | + redisCatchStorage.updateDevice(deviceInStore); |
| 610 | } | 601 | } |
| 611 | 602 | ||
| 612 | @Override | 603 | @Override |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| @@ -20,6 +20,8 @@ import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; | @@ -20,6 +20,8 @@ import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; | ||
| 20 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | 20 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 21 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; | 21 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 22 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | 22 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 23 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; | ||
| 24 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; | ||
| 23 | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | 25 | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| 24 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | 26 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 25 | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; | 27 | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; |
| @@ -29,6 +31,10 @@ import com.genersoft.iot.vmp.media.zlm.*; | @@ -29,6 +31,10 @@ import com.genersoft.iot.vmp.media.zlm.*; | ||
| 29 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | 31 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 30 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | 32 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; |
| 31 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | 33 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 34 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | ||
| 35 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRecordMp4; | ||
| 36 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | ||
| 37 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | ||
| 32 | import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | 38 | import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; |
| 33 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; | 39 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; |
| 34 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; | 40 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; |
| @@ -39,9 +45,12 @@ import com.genersoft.iot.vmp.service.bean.InviteErrorCode; | @@ -39,9 +45,12 @@ import com.genersoft.iot.vmp.service.bean.InviteErrorCode; | ||
| 39 | import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; | 45 | import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; |
| 40 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; | 46 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 41 | import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; | 47 | import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; |
| 48 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | ||
| 49 | +import com.genersoft.iot.vmp.service.bean.ErrorCallback; | ||
| 50 | +import com.genersoft.iot.vmp.service.bean.InviteErrorCode; | ||
| 51 | +import com.genersoft.iot.vmp.service.bean.SSRCInfo; | ||
| 42 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | 52 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 43 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | 53 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 44 | -import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; | ||
| 45 | import com.genersoft.iot.vmp.utils.CloudRecordUtils; | 54 | import com.genersoft.iot.vmp.utils.CloudRecordUtils; |
| 46 | import com.genersoft.iot.vmp.utils.DateUtil; | 55 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 47 | import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; | 56 | import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; |
| @@ -80,7 +89,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -80,7 +89,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 80 | private IVideoManagerStorage storager; | 89 | private IVideoManagerStorage storager; |
| 81 | 90 | ||
| 82 | @Autowired | 91 | @Autowired |
| 83 | - private SIPCommander cmder; | 92 | + private ISIPCommander cmder; |
| 84 | 93 | ||
| 85 | @Autowired | 94 | @Autowired |
| 86 | private AudioBroadcastManager audioBroadcastManager; | 95 | private AudioBroadcastManager audioBroadcastManager; |
| @@ -122,6 +131,9 @@ public class PlayServiceImpl implements IPlayService { | @@ -122,6 +131,9 @@ public class PlayServiceImpl implements IPlayService { | ||
| 122 | private UserSetting userSetting; | 131 | private UserSetting userSetting; |
| 123 | 132 | ||
| 124 | @Autowired | 133 | @Autowired |
| 134 | + private IDeviceChannelService channelService; | ||
| 135 | + | ||
| 136 | + @Autowired | ||
| 125 | private SipConfig sipConfig; | 137 | private SipConfig sipConfig; |
| 126 | 138 | ||
| 127 | @Autowired | 139 | @Autowired |
| @@ -163,6 +175,11 @@ public class PlayServiceImpl implements IPlayService { | @@ -163,6 +175,11 @@ public class PlayServiceImpl implements IPlayService { | ||
| 163 | logger.warn("[点播] 单端口收流时不支持TCP主动方式收流 deviceId: {},channelId:{}", deviceId, channelId); | 175 | logger.warn("[点播] 单端口收流时不支持TCP主动方式收流 deviceId: {},channelId:{}", deviceId, channelId); |
| 164 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "单端口收流时不支持TCP主动方式收流"); | 176 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "单端口收流时不支持TCP主动方式收流"); |
| 165 | } | 177 | } |
| 178 | + DeviceChannel channel = channelService.getOne(deviceId, channelId); | ||
| 179 | + if (channel == null) { | ||
| 180 | + logger.warn("[点播] 未找到通道 deviceId: {},channelId:{}", deviceId, channelId); | ||
| 181 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到通道"); | ||
| 182 | + } | ||
| 166 | InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); | 183 | InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); |
| 167 | if (inviteInfo != null ) { | 184 | if (inviteInfo != null ) { |
| 168 | if (inviteInfo.getStreamInfo() == null) { | 185 | if (inviteInfo.getStreamInfo() == null) { |
| @@ -211,7 +228,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -211,7 +228,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 211 | null); | 228 | null); |
| 212 | return null; | 229 | return null; |
| 213 | } | 230 | } |
| 214 | - play(mediaServerItem, ssrcInfo, device, channelId, callback); | 231 | + play(mediaServerItem, ssrcInfo, device, channel, callback); |
| 215 | return ssrcInfo; | 232 | return ssrcInfo; |
| 216 | } | 233 | } |
| 217 | 234 | ||
| @@ -358,7 +375,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -358,7 +375,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 358 | 375 | ||
| 359 | 376 | ||
| 360 | @Override | 377 | @Override |
| 361 | - public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, | 378 | + public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel, |
| 362 | ErrorCallback<Object> callback) { | 379 | ErrorCallback<Object> callback) { |
| 363 | 380 | ||
| 364 | if (mediaServerItem == null || ssrcInfo == null) { | 381 | if (mediaServerItem == null || ssrcInfo == null) { |
| @@ -367,111 +384,109 @@ public class PlayServiceImpl implements IPlayService { | @@ -367,111 +384,109 @@ public class PlayServiceImpl implements IPlayService { | ||
| 367 | null); | 384 | null); |
| 368 | return; | 385 | return; |
| 369 | } | 386 | } |
| 370 | - logger.info("[点播开始] deviceId: {}, channelId: {},码流类型:{}, 收流端口: {}, STREAM:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", | ||
| 371 | - device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", ssrcInfo.getPort(), ssrcInfo.getStream(), | 387 | + logger.info("[点播开始] deviceId: {}, channelId: {},码流类型:{}, 收流端口: {}, 码流:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", |
| 388 | + device.getDeviceId(), channel.getChannelId(), channel.getStreamIdentification(), ssrcInfo.getPort(), ssrcInfo.getStream(), | ||
| 372 | device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); | 389 | device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); |
| 373 | //端口获取失败的ssrcInfo 没有必要发送点播指令 | 390 | //端口获取失败的ssrcInfo 没有必要发送点播指令 |
| 374 | if (ssrcInfo.getPort() <= 0) { | 391 | if (ssrcInfo.getPort() <= 0) { |
| 375 | - logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo); | 392 | + logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channel.getChannelId(), ssrcInfo); |
| 376 | // 释放ssrc | 393 | // 释放ssrc |
| 377 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | 394 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| 378 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | 395 | + streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream()); |
| 379 | 396 | ||
| 380 | callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null); | 397 | callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null); |
| 381 | - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, | 398 | + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null, |
| 382 | InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null); | 399 | InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "点播端口分配异常", null); |
| 383 | return; | 400 | return; |
| 384 | } | 401 | } |
| 385 | 402 | ||
| 386 | // 初始化redis中的invite消息状态 | 403 | // 初始化redis中的invite消息状态 |
| 387 | - InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo, | 404 | + InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream(), ssrcInfo, |
| 388 | mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY, | 405 | mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY, |
| 389 | InviteSessionStatus.ready); | 406 | InviteSessionStatus.ready); |
| 390 | - inviteInfo.setSubStream(device.isSwitchPrimarySubStream()); | ||
| 391 | inviteStreamService.updateInviteInfo(inviteInfo); | 407 | inviteStreamService.updateInviteInfo(inviteInfo); |
| 392 | // 超时处理 | 408 | // 超时处理 |
| 393 | String timeOutTaskKey = UUID.randomUUID().toString(); | 409 | String timeOutTaskKey = UUID.randomUUID().toString(); |
| 394 | dynamicTask.startDelay(timeOutTaskKey, () -> { | 410 | dynamicTask.startDelay(timeOutTaskKey, () -> { |
| 395 | // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况 | 411 | // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况 |
| 396 | - InviteInfo inviteInfoForTimeOut = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId); | 412 | + InviteInfo inviteInfoForTimeOut = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId()); |
| 397 | if (inviteInfoForTimeOut == null || inviteInfoForTimeOut.getStreamInfo() == null) { | 413 | if (inviteInfoForTimeOut == null || inviteInfoForTimeOut.getStreamInfo() == null) { |
| 398 | - logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流类型:{},端口:{}, SSRC: {}", | ||
| 399 | - device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", | 414 | + logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流:{},端口:{}, SSRC: {}", |
| 415 | + device.getDeviceId(), channel.getChannelId(), channel.getStreamIdentification(), | ||
| 400 | ssrcInfo.getPort(), ssrcInfo.getSsrc()); | 416 | ssrcInfo.getPort(), ssrcInfo.getSsrc()); |
| 401 | 417 | ||
| 402 | callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null); | 418 | callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null); |
| 403 | - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, | 419 | + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null, |
| 404 | InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null); | 420 | InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null); |
| 405 | - inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId); | 421 | + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId()); |
| 406 | 422 | ||
| 407 | try { | 423 | try { |
| 408 | - cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); | ||
| 409 | - } catch (InvalidArgumentException | ParseException | SipException | | ||
| 410 | - SsrcTransactionNotFoundException e) { | 424 | + cmder.streamByeCmd(device, channel.getChannelId(), ssrcInfo.getStream(), null); |
| 425 | + } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { | ||
| 411 | logger.error("[点播超时], 发送BYE失败 {}", e.getMessage()); | 426 | logger.error("[点播超时], 发送BYE失败 {}", e.getMessage()); |
| 412 | } finally { | 427 | } finally { |
| 413 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | 428 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| 414 | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); | 429 | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); |
| 415 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | 430 | + streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream()); |
| 416 | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); | 431 | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); |
| 417 | // 取消订阅消息监听 | 432 | // 取消订阅消息监听 |
| 418 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); | 433 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); |
| 419 | subscribe.removeSubscribe(hookSubscribe); | 434 | subscribe.removeSubscribe(hookSubscribe); |
| 420 | } | 435 | } |
| 421 | }else { | 436 | }else { |
| 422 | - logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流类型:{},端口:{}, SSRC: {}", | ||
| 423 | - device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", | 437 | + logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流:{},端口:{}, SSRC: {}", |
| 438 | + device.getDeviceId(), channel.getChannelId(), channel.getStreamIdentification(), | ||
| 424 | ssrcInfo.getPort(), ssrcInfo.getSsrc()); | 439 | ssrcInfo.getPort(), ssrcInfo.getSsrc()); |
| 425 | 440 | ||
| 426 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | 441 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| 427 | 442 | ||
| 428 | mediaServerService.closeRTPServer(mediaServerItem.getId(), ssrcInfo.getStream()); | 443 | mediaServerService.closeRTPServer(mediaServerItem.getId(), ssrcInfo.getStream()); |
| 429 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | 444 | + streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream()); |
| 430 | } | 445 | } |
| 431 | }, userSetting.getPlayTimeout()); | 446 | }, userSetting.getPlayTimeout()); |
| 432 | 447 | ||
| 433 | try { | 448 | try { |
| 434 | - cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInuse, hookParam ) -> { | 449 | + cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channel, (mediaServerItemInuse, hookParam ) -> { |
| 435 | logger.info("收到订阅消息: " + hookParam); | 450 | logger.info("收到订阅消息: " + hookParam); |
| 436 | dynamicTask.stop(timeOutTaskKey); | 451 | dynamicTask.stop(timeOutTaskKey); |
| 437 | // hook响应 | 452 | // hook响应 |
| 438 | - StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, hookParam, device.getDeviceId(), channelId); | 453 | + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, hookParam, device.getDeviceId(), channel.getChannelId()); |
| 439 | if (streamInfo == null){ | 454 | if (streamInfo == null){ |
| 440 | callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), | 455 | callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), |
| 441 | InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null); | 456 | InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null); |
| 442 | - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, | 457 | + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null, |
| 443 | InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), | 458 | InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), |
| 444 | InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null); | 459 | InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null); |
| 445 | return; | 460 | return; |
| 446 | } | 461 | } |
| 447 | callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); | 462 | callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); |
| 448 | - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, | 463 | + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null, |
| 449 | InviteErrorCode.SUCCESS.getCode(), | 464 | InviteErrorCode.SUCCESS.getCode(), |
| 450 | InviteErrorCode.SUCCESS.getMsg(), | 465 | InviteErrorCode.SUCCESS.getMsg(), |
| 451 | streamInfo); | 466 | streamInfo); |
| 452 | - logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channelId, | ||
| 453 | - device.isSwitchPrimarySubStream() ? "辅码流" : "主码流"); | ||
| 454 | - snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channelId, ssrcInfo.getStream()); | 467 | + logger.info("[点播成功] deviceId: {}, channelId:{}, 码流类型:{}", device.getDeviceId(), channel.getChannelId(), |
| 468 | + channel.getStreamIdentification()); | ||
| 469 | + snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream()); | ||
| 455 | }, (eventResult) -> { | 470 | }, (eventResult) -> { |
| 456 | // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 | 471 | // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 |
| 457 | - InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, | 472 | + InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channel.getChannelId(), |
| 458 | timeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAY); | 473 | timeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAY); |
| 459 | }, (event) -> { | 474 | }, (event) -> { |
| 460 | - logger.info("[点播失败] deviceId: {}, channelId:{}, {}: {}", device.getDeviceId(), channelId, event.statusCode, event.msg); | 475 | + logger.info("[点播失败] deviceId: {}, channelId:{}, {}: {}", device.getDeviceId(), channel.getChannelId(), event.statusCode, event.msg); |
| 461 | dynamicTask.stop(timeOutTaskKey); | 476 | dynamicTask.stop(timeOutTaskKey); |
| 462 | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); | 477 | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); |
| 463 | // 释放ssrc | 478 | // 释放ssrc |
| 464 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | 479 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| 465 | 480 | ||
| 466 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | 481 | + streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream()); |
| 467 | 482 | ||
| 468 | callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(), | 483 | callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(), |
| 469 | String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null); | 484 | String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null); |
| 470 | - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, | 485 | + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null, |
| 471 | InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(), | 486 | InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(), |
| 472 | String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null); | 487 | String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg), null); |
| 473 | 488 | ||
| 474 | - inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId); | 489 | + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId()); |
| 475 | }); | 490 | }); |
| 476 | } catch (InvalidArgumentException | SipException | ParseException e) { | 491 | } catch (InvalidArgumentException | SipException | ParseException e) { |
| 477 | 492 | ||
| @@ -481,15 +496,15 @@ public class PlayServiceImpl implements IPlayService { | @@ -481,15 +496,15 @@ public class PlayServiceImpl implements IPlayService { | ||
| 481 | // 释放ssrc | 496 | // 释放ssrc |
| 482 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | 497 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); |
| 483 | 498 | ||
| 484 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | 499 | + streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream()); |
| 485 | 500 | ||
| 486 | callback.run(InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(), | 501 | callback.run(InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(), |
| 487 | InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null); | 502 | InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null); |
| 488 | - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, | 503 | + inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null, |
| 489 | InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(), | 504 | InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(), |
| 490 | InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null); | 505 | InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null); |
| 491 | 506 | ||
| 492 | - inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId); | 507 | + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId()); |
| 493 | } | 508 | } |
| 494 | } | 509 | } |
| 495 | 510 | ||
| @@ -626,7 +641,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -626,7 +641,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 626 | 641 | ||
| 627 | @Override | 642 | @Override |
| 628 | public void playBack(String deviceId, String channelId, String startTime, | 643 | public void playBack(String deviceId, String channelId, String startTime, |
| 629 | - String endTime, ErrorCallback<Object> callback) { | 644 | + String endTime, ErrorCallback<Object> callback) { |
| 630 | Device device = storager.queryVideoDevice(deviceId); | 645 | Device device = storager.queryVideoDevice(deviceId); |
| 631 | if (device == null) { | 646 | if (device == null) { |
| 632 | logger.warn("[录像回放] 未找到设备 deviceId: {},channelId:{}", deviceId, channelId); | 647 | logger.warn("[录像回放] 未找到设备 deviceId: {},channelId:{}", deviceId, channelId); |
| @@ -651,8 +666,8 @@ public class PlayServiceImpl implements IPlayService { | @@ -651,8 +666,8 @@ public class PlayServiceImpl implements IPlayService { | ||
| 651 | 666 | ||
| 652 | @Override | 667 | @Override |
| 653 | public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, | 668 | public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, |
| 654 | - String deviceId, String channelId, String startTime, | ||
| 655 | - String endTime, ErrorCallback<Object> callback) { | 669 | + String deviceId, String channelId, String startTime, |
| 670 | + String endTime, ErrorCallback<Object> callback) { | ||
| 656 | if (mediaServerItem == null || ssrcInfo == null) { | 671 | if (mediaServerItem == null || ssrcInfo == null) { |
| 657 | callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(), | 672 | callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(), |
| 658 | InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(), | 673 | InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(), |
| @@ -1548,16 +1563,16 @@ public class PlayServiceImpl implements IPlayService { | @@ -1548,16 +1563,16 @@ public class PlayServiceImpl implements IPlayService { | ||
| 1548 | 1563 | ||
| 1549 | MediaServerItem newMediaServerItem = getNewMediaServerItem(device); | 1564 | MediaServerItem newMediaServerItem = getNewMediaServerItem(device); |
| 1550 | play(newMediaServerItem, deviceId, channelId, null, (code, msg, data)->{ | 1565 | play(newMediaServerItem, deviceId, channelId, null, (code, msg, data)->{ |
| 1551 | - if (code == InviteErrorCode.SUCCESS.getCode()) { | ||
| 1552 | - InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); | ||
| 1553 | - if (inviteInfoForPlay != null && inviteInfoForPlay.getStreamInfo() != null) { | ||
| 1554 | - getSnap(deviceId, channelId, fileName, errorCallback); | ||
| 1555 | - }else { | ||
| 1556 | - errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null); | ||
| 1557 | - } | ||
| 1558 | - }else { | ||
| 1559 | - errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null); | ||
| 1560 | - } | 1566 | + if (code == InviteErrorCode.SUCCESS.getCode()) { |
| 1567 | + InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); | ||
| 1568 | + if (inviteInfoForPlay != null && inviteInfoForPlay.getStreamInfo() != null) { | ||
| 1569 | + getSnap(deviceId, channelId, fileName, errorCallback); | ||
| 1570 | + }else { | ||
| 1571 | + errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null); | ||
| 1572 | + } | ||
| 1573 | + }else { | ||
| 1574 | + errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null); | ||
| 1575 | + } | ||
| 1561 | }); | 1576 | }); |
| 1562 | } | 1577 | } |
| 1563 | 1578 |
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
| @@ -20,11 +20,11 @@ public interface DeviceChannelMapper { | @@ -20,11 +20,11 @@ public interface DeviceChannelMapper { | ||
| 20 | @Insert("INSERT INTO wvp_device_channel (channel_id, device_id, name, manufacture, model, owner, civil_code, block, " + | 20 | @Insert("INSERT INTO wvp_device_channel (channel_id, device_id, name, manufacture, model, owner, civil_code, block, " + |
| 21 | "address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " + | 21 | "address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " + |
| 22 | "ip_address, port, password, ptz_type, status, stream_id, longitude, latitude, longitude_gcj02, latitude_gcj02, " + | 22 | "ip_address, port, password, ptz_type, status, stream_id, longitude, latitude, longitude_gcj02, latitude_gcj02, " + |
| 23 | - "longitude_wgs84, latitude_wgs84, has_audio, create_time, update_time, business_group_id, gps_time) " + | 23 | + "longitude_wgs84, latitude_wgs84, has_audio, create_time, update_time, business_group_id, gps_time, stream_identification) " + |
| 24 | "VALUES (#{channelId}, #{deviceId}, #{name}, #{manufacture}, #{model}, #{owner}, #{civilCode}, #{block}," + | 24 | "VALUES (#{channelId}, #{deviceId}, #{name}, #{manufacture}, #{model}, #{owner}, #{civilCode}, #{block}," + |
| 25 | "#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{secrecy}, " + | 25 | "#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{secrecy}, " + |
| 26 | "#{ipAddress}, #{port}, #{password}, #{PTZType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " + | 26 | "#{ipAddress}, #{port}, #{password}, #{PTZType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " + |
| 27 | - "#{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{hasAudio}, #{createTime}, #{updateTime}, #{businessGroupId}, #{gpsTime})") | 27 | + "#{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{hasAudio}, #{createTime}, #{updateTime}, #{businessGroupId}, #{gpsTime}, #{streamIdentification})") |
| 28 | int add(DeviceChannel channel); | 28 | int add(DeviceChannel channel); |
| 29 | 29 | ||
| 30 | @Update(value = {" <script>" + | 30 | @Update(value = {" <script>" + |
| @@ -60,6 +60,7 @@ public interface DeviceChannelMapper { | @@ -60,6 +60,7 @@ public interface DeviceChannelMapper { | ||
| 60 | "<if test='latitudeWgs84 != null'>, latitude_wgs84=#{latitudeWgs84}</if>" + | 60 | "<if test='latitudeWgs84 != null'>, latitude_wgs84=#{latitudeWgs84}</if>" + |
| 61 | "<if test='businessGroupId != null'>, business_group_id=#{businessGroupId}</if>" + | 61 | "<if test='businessGroupId != null'>, business_group_id=#{businessGroupId}</if>" + |
| 62 | "<if test='gpsTime != null'>, gps_time=#{gpsTime}</if>" + | 62 | "<if test='gpsTime != null'>, gps_time=#{gpsTime}</if>" + |
| 63 | + "<if test='streamIdentification != null'>, stream_identification=#{streamIdentification}</if>" + | ||
| 63 | "WHERE device_id=#{deviceId} AND channel_id=#{channelId}"+ | 64 | "WHERE device_id=#{deviceId} AND channel_id=#{channelId}"+ |
| 64 | " </script>"}) | 65 | " </script>"}) |
| 65 | int update(DeviceChannel channel); | 66 | int update(DeviceChannel channel); |
| @@ -102,6 +103,7 @@ public interface DeviceChannelMapper { | @@ -102,6 +103,7 @@ public interface DeviceChannelMapper { | ||
| 102 | "dc.longitude_wgs84, " + | 103 | "dc.longitude_wgs84, " + |
| 103 | "dc.latitude_wgs84, " + | 104 | "dc.latitude_wgs84, " + |
| 104 | "dc.business_group_id, " + | 105 | "dc.business_group_id, " + |
| 106 | + "dc.stream_identification, " + | ||
| 105 | "dc.gps_time " + | 107 | "dc.gps_time " + |
| 106 | "from " + | 108 | "from " + |
| 107 | "wvp_device_channel dc " + | 109 | "wvp_device_channel dc " + |
| @@ -241,7 +243,7 @@ public interface DeviceChannelMapper { | @@ -241,7 +243,7 @@ public interface DeviceChannelMapper { | ||
| 241 | "(channel_id, device_id, name, manufacture, model, owner, civil_code, block, sub_count, " + | 243 | "(channel_id, device_id, name, manufacture, model, owner, civil_code, block, sub_count, " + |
| 242 | " address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " + | 244 | " address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " + |
| 243 | " ip_address,port,password,ptz_type,status,stream_id,longitude,latitude,longitude_gcj02,latitude_gcj02,"+ | 245 | " ip_address,port,password,ptz_type,status,stream_id,longitude,latitude,longitude_gcj02,latitude_gcj02,"+ |
| 244 | - " longitude_wgs84,latitude_wgs84,has_audio,create_time,update_time,business_group_id,gps_time)"+ | 246 | + " longitude_wgs84,latitude_wgs84,has_audio,create_time,update_time,business_group_id,gps_time,stream_identification)"+ |
| 245 | "values " + | 247 | "values " + |
| 246 | "<foreach collection='addChannels' index='index' item='item' separator=','> " + | 248 | "<foreach collection='addChannels' index='index' item='item' separator=','> " + |
| 247 | "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " + | 249 | "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " + |
| @@ -251,7 +253,7 @@ public interface DeviceChannelMapper { | @@ -251,7 +253,7 @@ public interface DeviceChannelMapper { | ||
| 251 | "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " + | 253 | "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " + |
| 252 | "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " + | 254 | "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " + |
| 253 | "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " + | 255 | "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " + |
| 254 | - "#{item.businessGroupId}, #{item.gpsTime}) " + | 256 | + "#{item.businessGroupId}, #{item.gpsTime}, #{item.streamIdentification}) " + |
| 255 | "</foreach> " + | 257 | "</foreach> " + |
| 256 | "</script>") | 258 | "</script>") |
| 257 | int batchAdd(@Param("addChannels") List<DeviceChannel> addChannels); | 259 | int batchAdd(@Param("addChannels") List<DeviceChannel> addChannels); |
| @@ -349,6 +351,7 @@ public interface DeviceChannelMapper { | @@ -349,6 +351,7 @@ public interface DeviceChannelMapper { | ||
| 349 | "<if test='item.latitudeWgs84 != null'>, latitude_wgs84=#{item.latitudeWgs84}</if>" + | 351 | "<if test='item.latitudeWgs84 != null'>, latitude_wgs84=#{item.latitudeWgs84}</if>" + |
| 350 | "<if test='item.businessGroupId != null'>, business_group_id=#{item.businessGroupId}</if>" + | 352 | "<if test='item.businessGroupId != null'>, business_group_id=#{item.businessGroupId}</if>" + |
| 351 | "<if test='item.gpsTime != null'>, gps_time=#{item.gpsTime}</if>" + | 353 | "<if test='item.gpsTime != null'>, gps_time=#{item.gpsTime}</if>" + |
| 354 | + "<if test='item.streamIdentification != null'>, stream_identification=#{item.streamIdentification}</if>" + | ||
| 352 | "<if test='item.id > 0'>WHERE id=#{item.id}</if>" + | 355 | "<if test='item.id > 0'>WHERE id=#{item.id}</if>" + |
| 353 | "<if test='item.id == 0'>WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}</if>" + | 356 | "<if test='item.id == 0'>WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}</if>" + |
| 354 | "</foreach>" + | 357 | "</foreach>" + |
| @@ -542,4 +545,9 @@ public interface DeviceChannelMapper { | @@ -542,4 +545,9 @@ public interface DeviceChannelMapper { | ||
| 542 | " </script>"}) | 545 | " </script>"}) |
| 543 | List<DeviceChannel> getSubChannelsByDeviceId(@Param("deviceId") String deviceId, @Param("parentId") String parentId, @Param("onlyCatalog") boolean onlyCatalog); | 546 | List<DeviceChannel> getSubChannelsByDeviceId(@Param("deviceId") String deviceId, @Param("parentId") String parentId, @Param("onlyCatalog") boolean onlyCatalog); |
| 544 | 547 | ||
| 548 | + @Update("<script>" + | ||
| 549 | + "UPDATE wvp_device_channel SET stream_identification=#{streamIdentification} WHERE device_id=#{deviceId}" + | ||
| 550 | + " <if test='channelId != null'> and channel_id = #{channelId} </if>" + | ||
| 551 | + "</script>") | ||
| 552 | + void updateChannelStreamIdentification(DeviceChannel channel); | ||
| 545 | } | 553 | } |
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
| @@ -43,7 +43,6 @@ public interface DeviceMapper { | @@ -43,7 +43,6 @@ public interface DeviceMapper { | ||
| 43 | "geo_coord_sys," + | 43 | "geo_coord_sys," + |
| 44 | "on_line," + | 44 | "on_line," + |
| 45 | "media_server_id," + | 45 | "media_server_id," + |
| 46 | - "switch_primary_sub_stream," + | ||
| 47 | "broadcast_push_after_ack," + | 46 | "broadcast_push_after_ack," + |
| 48 | "(SELECT count(0) FROM wvp_device_channel WHERE device_id=wvp_device.device_id) as channel_count "+ | 47 | "(SELECT count(0) FROM wvp_device_channel WHERE device_id=wvp_device.device_id) as channel_count "+ |
| 49 | " FROM wvp_device WHERE device_id = #{deviceId}") | 48 | " FROM wvp_device WHERE device_id = #{deviceId}") |
| @@ -163,7 +162,6 @@ public interface DeviceMapper { | @@ -163,7 +162,6 @@ public interface DeviceMapper { | ||
| 163 | "geo_coord_sys,"+ | 162 | "geo_coord_sys,"+ |
| 164 | "on_line,"+ | 163 | "on_line,"+ |
| 165 | "media_server_id,"+ | 164 | "media_server_id,"+ |
| 166 | - "switch_primary_sub_stream switchPrimarySubStream,"+ | ||
| 167 | "(SELECT count(0) FROM wvp_device_channel WHERE device_id=de.device_id) as channel_count " + | 165 | "(SELECT count(0) FROM wvp_device_channel WHERE device_id=de.device_id) as channel_count " + |
| 168 | "FROM wvp_device de" + | 166 | "FROM wvp_device de" + |
| 169 | "<if test=\"onLine != null\"> where on_line=${onLine}</if>"+ | 167 | "<if test=\"onLine != null\"> where on_line=${onLine}</if>"+ |
| @@ -256,7 +254,6 @@ public interface DeviceMapper { | @@ -256,7 +254,6 @@ public interface DeviceMapper { | ||
| 256 | "<if test=\"asMessageChannel != null\">, as_message_channel=#{asMessageChannel}</if>" + | 254 | "<if test=\"asMessageChannel != null\">, as_message_channel=#{asMessageChannel}</if>" + |
| 257 | "<if test=\"broadcastPushAfterAck != null\">, broadcast_push_after_ack=#{broadcastPushAfterAck}</if>" + | 255 | "<if test=\"broadcastPushAfterAck != null\">, broadcast_push_after_ack=#{broadcastPushAfterAck}</if>" + |
| 258 | "<if test=\"geoCoordSys != null\">, geo_coord_sys=#{geoCoordSys}</if>" + | 256 | "<if test=\"geoCoordSys != null\">, geo_coord_sys=#{geoCoordSys}</if>" + |
| 259 | - "<if test=\"switchPrimarySubStream != null\">, switch_primary_sub_stream=#{switchPrimarySubStream}</if>" + | ||
| 260 | "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" + | 257 | "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" + |
| 261 | "WHERE device_id=#{deviceId}"+ | 258 | "WHERE device_id=#{deviceId}"+ |
| 262 | " </script>"}) | 259 | " </script>"}) |
| @@ -275,8 +272,7 @@ public interface DeviceMapper { | @@ -275,8 +272,7 @@ public interface DeviceMapper { | ||
| 275 | "broadcastPushAfterAck,"+ | 272 | "broadcastPushAfterAck,"+ |
| 276 | "geo_coord_sys,"+ | 273 | "geo_coord_sys,"+ |
| 277 | "on_line,"+ | 274 | "on_line,"+ |
| 278 | - "media_server_id,"+ | ||
| 279 | - "switch_primary_sub_stream"+ | 275 | + "media_server_id"+ |
| 280 | ") VALUES (" + | 276 | ") VALUES (" + |
| 281 | "#{deviceId}," + | 277 | "#{deviceId}," + |
| 282 | "#{name}," + | 278 | "#{name}," + |
| @@ -290,8 +286,7 @@ public interface DeviceMapper { | @@ -290,8 +286,7 @@ public interface DeviceMapper { | ||
| 290 | "#{broadcastPushAfterAck}," + | 286 | "#{broadcastPushAfterAck}," + |
| 291 | "#{geoCoordSys}," + | 287 | "#{geoCoordSys}," + |
| 292 | "#{onLine}," + | 288 | "#{onLine}," + |
| 293 | - "#{mediaServerId}," + | ||
| 294 | - "#{switchPrimarySubStream}" + | 289 | + "#{mediaServerId}" + |
| 295 | ")") | 290 | ")") |
| 296 | void addCustomDevice(Device device); | 291 | void addCustomDevice(Device device); |
| 297 | 292 |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
| @@ -153,10 +153,7 @@ public class MobilePositionController { | @@ -153,10 +153,7 @@ public class MobilePositionController { | ||
| 153 | Device device = storager.queryVideoDevice(deviceId); | 153 | Device device = storager.queryVideoDevice(deviceId); |
| 154 | device.setSubscribeCycleForMobilePosition(Integer.parseInt(expires)); | 154 | device.setSubscribeCycleForMobilePosition(Integer.parseInt(expires)); |
| 155 | device.setMobilePositionSubmissionInterval(Integer.parseInt(interval)); | 155 | device.setMobilePositionSubmissionInterval(Integer.parseInt(interval)); |
| 156 | - deviceService.updateDevice(device); | ||
| 157 | - if (!deviceService.removeMobilePositionSubscribe(device)) { | ||
| 158 | - throw new ControllerException(ErrorCode.ERROR100); | ||
| 159 | - } | 156 | + deviceService.updateCustomDevice(device); |
| 160 | } | 157 | } |
| 161 | 158 | ||
| 162 | /** | 159 | /** |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
| @@ -199,7 +199,7 @@ public class DeviceQuery { | @@ -199,7 +199,7 @@ public class DeviceQuery { | ||
| 199 | Runnable runnable = dynamicTask.get(key); | 199 | Runnable runnable = dynamicTask.get(key); |
| 200 | if (runnable instanceof ISubscribeTask) { | 200 | if (runnable instanceof ISubscribeTask) { |
| 201 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; | 201 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; |
| 202 | - subscribeTask.stop(); | 202 | + subscribeTask.stop(null); |
| 203 | } | 203 | } |
| 204 | dynamicTask.stop(key); | 204 | dynamicTask.stop(key); |
| 205 | } | 205 | } |
| @@ -264,6 +264,14 @@ public class DeviceQuery { | @@ -264,6 +264,14 @@ public class DeviceQuery { | ||
| 264 | deviceChannelService.updateChannel(deviceId, channel); | 264 | deviceChannelService.updateChannel(deviceId, channel); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | + @Operation(summary = "修改通道的码流类型", security = @SecurityRequirement(name = JwtUtils.HEADER)) | ||
| 268 | + @Parameter(name = "deviceId", description = "设备国标编号", required = true) | ||
| 269 | + @Parameter(name = "channel", description = "通道信息", required = true) | ||
| 270 | + @PostMapping("/channel/stream/identification/update/") | ||
| 271 | + public void updateChannelStreamIdentification(DeviceChannel channel){ | ||
| 272 | + deviceChannelService.updateChannelStreamIdentification(channel); | ||
| 273 | + } | ||
| 274 | + | ||
| 267 | /** | 275 | /** |
| 268 | * 修改数据流传输模式 | 276 | * 修改数据流传输模式 |
| 269 | * @param deviceId 设备id | 277 | * @param deviceId 设备id |
web_src/src/components/channelList.vue
| @@ -13,24 +13,30 @@ | @@ -13,24 +13,30 @@ | ||
| 13 | prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input> | 13 | prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input> |
| 14 | 14 | ||
| 15 | 通道类型: | 15 | 通道类型: |
| 16 | - <el-select size="mini" @change="search" style="margin-right: 1rem;" v-model="channelType" placeholder="请选择" | 16 | + <el-select size="mini" @change="search" style="width: 8rem; margin-right: 1rem;" v-model="channelType" placeholder="请选择" |
| 17 | default-first-option> | 17 | default-first-option> |
| 18 | <el-option label="全部" value=""></el-option> | 18 | <el-option label="全部" value=""></el-option> |
| 19 | <el-option label="设备" value="false"></el-option> | 19 | <el-option label="设备" value="false"></el-option> |
| 20 | <el-option label="子目录" value="true"></el-option> | 20 | <el-option label="子目录" value="true"></el-option> |
| 21 | </el-select> | 21 | </el-select> |
| 22 | 在线状态: | 22 | 在线状态: |
| 23 | - <el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="online" placeholder="请选择" | 23 | + <el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="search" v-model="online" placeholder="请选择" |
| 24 | default-first-option> | 24 | default-first-option> |
| 25 | <el-option label="全部" value=""></el-option> | 25 | <el-option label="全部" value=""></el-option> |
| 26 | <el-option label="在线" value="true"></el-option> | 26 | <el-option label="在线" value="true"></el-option> |
| 27 | <el-option label="离线" value="false"></el-option> | 27 | <el-option label="离线" value="false"></el-option> |
| 28 | </el-select> | 28 | </el-select> |
| 29 | - 清晰度: | ||
| 30 | - <el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="isSubStream" placeholder="请选择" | ||
| 31 | - default-first-option> | ||
| 32 | - <el-option label="原画" :value="false"></el-option> | ||
| 33 | - <el-option label="流畅" :value="true"></el-option> | 29 | + 码流类型重置: |
| 30 | + <el-select size="mini" style="width: 16rem; margin-right: 1rem;" @change="subStreamChange" v-model="subStream" | ||
| 31 | + placeholder="请选择码流类型" default-first-option > | ||
| 32 | + <el-option label="stream:0(主码流)" value="stream:0"></el-option> | ||
| 33 | + <el-option label="stream:1(子码流)" value="stream:1"></el-option> | ||
| 34 | + <el-option label="streamnumber:0(主码流-2022)" value="streamnumber:0"></el-option> | ||
| 35 | + <el-option label="streamnumber:1(子码流-2022)" value="streamnumber:1"></el-option> | ||
| 36 | + <el-option label="streamprofile:0(主码流-大华)" value="streamprofile:0"></el-option> | ||
| 37 | + <el-option label="streamprofile:1(子码流-大华)" value="streamprofile:1"></el-option> | ||
| 38 | + <el-option label="streamMode:main(主码流-水星+TP-LINK)" value="streamMode:main"></el-option> | ||
| 39 | + <el-option label="streamMode:sub(子码流-水星+TP-LINK)" value="streamMode:sub"></el-option> | ||
| 34 | </el-select> | 40 | </el-select> |
| 35 | </div> | 41 | </div> |
| 36 | <el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button> | 42 | <el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button> |
| @@ -46,11 +52,11 @@ | @@ -46,11 +52,11 @@ | ||
| 46 | <el-main style="padding: 5px;"> | 52 | <el-main style="padding: 5px;"> |
| 47 | <el-table ref="channelListTable" :data="deviceChannelList" :height="winHeight" style="width: 100%" | 53 | <el-table ref="channelListTable" :data="deviceChannelList" :height="winHeight" style="width: 100%" |
| 48 | header-row-class-name="table-header"> | 54 | header-row-class-name="table-header"> |
| 49 | - <el-table-column prop="channelId" label="通道编号" min-width="200"> | 55 | + <el-table-column prop="channelId" label="通道编号" min-width="180"> |
| 50 | </el-table-column> | 56 | </el-table-column> |
| 51 | - <el-table-column prop="deviceId" label="设备编号" min-width="200"> | 57 | + <el-table-column prop="deviceId" label="设备编号" min-width="180"> |
| 52 | </el-table-column> | 58 | </el-table-column> |
| 53 | - <el-table-column prop="name" label="通道名称" min-width="200"> | 59 | + <el-table-column prop="name" label="通道名称" min-width="180"> |
| 54 | <template v-slot:default="scope"> | 60 | <template v-slot:default="scope"> |
| 55 | <el-input | 61 | <el-input |
| 56 | v-show="scope.row.edit" | 62 | v-show="scope.row.edit" |
| @@ -63,7 +69,7 @@ | @@ -63,7 +69,7 @@ | ||
| 63 | <span v-show="!scope.row.edit">{{ scope.row.name }}</span> | 69 | <span v-show="!scope.row.edit">{{ scope.row.name }}</span> |
| 64 | </template> | 70 | </template> |
| 65 | </el-table-column> | 71 | </el-table-column> |
| 66 | - <el-table-column label="快照" min-width="120"> | 72 | + <el-table-column label="快照" min-width="100"> |
| 67 | <template v-slot:default="scope"> | 73 | <template v-slot:default="scope"> |
| 68 | <el-image | 74 | <el-image |
| 69 | :src="getSnap(scope.row)" | 75 | :src="getSnap(scope.row)" |
| @@ -77,11 +83,11 @@ | @@ -77,11 +83,11 @@ | ||
| 77 | </el-image> | 83 | </el-image> |
| 78 | </template> | 84 | </template> |
| 79 | </el-table-column> | 85 | </el-table-column> |
| 80 | - <el-table-column prop="subCount" label="子节点数" min-width="120"> | 86 | + <el-table-column prop="subCount" label="子节点数" min-width="100"> |
| 81 | </el-table-column> | 87 | </el-table-column> |
| 82 | - <el-table-column prop="manufacture" label="厂家" min-width="120"> | 88 | + <el-table-column prop="manufacture" label="厂家" min-width="100"> |
| 83 | </el-table-column> | 89 | </el-table-column> |
| 84 | - <el-table-column label="位置信息" min-width="200"> | 90 | + <el-table-column label="位置信息" min-width="120"> |
| 85 | <template v-slot:default="scope"> | 91 | <template v-slot:default="scope"> |
| 86 | <el-input | 92 | <el-input |
| 87 | v-show="scope.row.edit" | 93 | v-show="scope.row.edit" |
| @@ -94,7 +100,7 @@ | @@ -94,7 +100,7 @@ | ||
| 94 | <span v-show="!scope.row.edit">{{ scope.row.location }}</span> | 100 | <span v-show="!scope.row.edit">{{ scope.row.location }}</span> |
| 95 | </template> | 101 | </template> |
| 96 | </el-table-column> | 102 | </el-table-column> |
| 97 | - <el-table-column prop="PTZType" label="云台类型" min-width="120"> | 103 | + <el-table-column prop="PTZType" label="云台类型" min-width="100"> |
| 98 | <template v-slot:default="scope"> | 104 | <template v-slot:default="scope"> |
| 99 | <el-select v-show="scope.row.edit" v-model="scope.row.PTZType" | 105 | <el-select v-show="scope.row.edit" v-model="scope.row.PTZType" |
| 100 | placeholder="云台类型" filterable> | 106 | placeholder="云台类型" filterable> |
| @@ -108,13 +114,28 @@ | @@ -108,13 +114,28 @@ | ||
| 108 | <div v-show="!scope.row.edit">{{ scope.row.PTZTypeText }}</div> | 114 | <div v-show="!scope.row.edit">{{ scope.row.PTZTypeText }}</div> |
| 109 | </template> | 115 | </template> |
| 110 | </el-table-column> | 116 | </el-table-column> |
| 111 | - <el-table-column label="开启音频" min-width="120"> | 117 | + <el-table-column label="开启音频" min-width="100"> |
| 112 | <template slot-scope="scope"> | 118 | <template slot-scope="scope"> |
| 113 | <el-switch @change="updateChannel(scope.row)" v-model="scope.row.hasAudio" active-color="#409EFF"> | 119 | <el-switch @change="updateChannel(scope.row)" v-model="scope.row.hasAudio" active-color="#409EFF"> |
| 114 | </el-switch> | 120 | </el-switch> |
| 115 | </template> | 121 | </template> |
| 116 | </el-table-column> | 122 | </el-table-column> |
| 117 | - <el-table-column label="状态" min-width="120"> | 123 | + <el-table-column label="码流类型" min-width="180"> |
| 124 | + <template slot-scope="scope"> | ||
| 125 | + <el-select size="mini" style="margin-right: 1rem;" @change="channelSubStreamChange(scope.row)" v-model="scope.row.streamIdentification" | ||
| 126 | + placeholder="请选择码流类型" default-first-option > | ||
| 127 | + <el-option label="stream:0(主码流)" value="stream:0"></el-option> | ||
| 128 | + <el-option label="stream:1(子码流)" value="stream:1"></el-option> | ||
| 129 | + <el-option label="streamnumber:0(主码流-2022)" value="streamnumber:0"></el-option> | ||
| 130 | + <el-option label="streamnumber:1(子码流-2022)" value="streamnumber:1"></el-option> | ||
| 131 | + <el-option label="streamprofile:0(主码流-大华)" value="streamprofile:0"></el-option> | ||
| 132 | + <el-option label="streamprofile:1(子码流-大华)" value="streamprofile:1"></el-option> | ||
| 133 | + <el-option label="streamMode:main(主码流-水星+TP-LINK)" value="streamMode:main"></el-option> | ||
| 134 | + <el-option label="streamMode:sub(子码流-水星+TP-LINK)" value="streamMode:sub"></el-option> | ||
| 135 | + </el-select> | ||
| 136 | + </template> | ||
| 137 | + </el-table-column> | ||
| 138 | + <el-table-column label="状态" min-width="100"> | ||
| 118 | <template slot-scope="scope"> | 139 | <template slot-scope="scope"> |
| 119 | <div slot="reference" class="name-wrapper"> | 140 | <div slot="reference" class="name-wrapper"> |
| 120 | <el-tag size="medium" v-if="scope.row.status === true">在线</el-tag> | 141 | <el-tag size="medium" v-if="scope.row.status === true">在线</el-tag> |
| @@ -122,8 +143,6 @@ | @@ -122,8 +143,6 @@ | ||
| 122 | </div> | 143 | </div> |
| 123 | </template> | 144 | </template> |
| 124 | </el-table-column> | 145 | </el-table-column> |
| 125 | - | ||
| 126 | - | ||
| 127 | <el-table-column label="操作" min-width="340" fixed="right"> | 146 | <el-table-column label="操作" min-width="340" fixed="right"> |
| 128 | <template slot-scope="scope"> | 147 | <template slot-scope="scope"> |
| 129 | <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-video-play" | 148 | <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-video-play" |
| @@ -213,7 +232,7 @@ export default { | @@ -213,7 +232,7 @@ export default { | ||
| 213 | searchSrt: "", | 232 | searchSrt: "", |
| 214 | channelType: "", | 233 | channelType: "", |
| 215 | online: "", | 234 | online: "", |
| 216 | - isSubStream: false, | 235 | + subStream: "", |
| 217 | winHeight: window.innerHeight - 200, | 236 | winHeight: window.innerHeight - 200, |
| 218 | currentPage: 1, | 237 | currentPage: 1, |
| 219 | count: 15, | 238 | count: 15, |
| @@ -495,6 +514,43 @@ export default { | @@ -495,6 +514,43 @@ export default { | ||
| 495 | console.log(JSON.stringify(res)); | 514 | console.log(JSON.stringify(res)); |
| 496 | }); | 515 | }); |
| 497 | }, | 516 | }, |
| 517 | + subStreamChange: function () { | ||
| 518 | + this.$confirm('确定重置所有通道的码流类型?', '提示', { | ||
| 519 | + confirmButtonText: '确定', | ||
| 520 | + cancelButtonText: '取消', | ||
| 521 | + type: 'warning' | ||
| 522 | + }).then(() => { | ||
| 523 | + this.$axios({ | ||
| 524 | + method: 'post', | ||
| 525 | + url: `/api/device/query/channel/stream/identification/update/`, | ||
| 526 | + params: { | ||
| 527 | + deviceId: this.deviceId, | ||
| 528 | + streamIdentification: this.subStream | ||
| 529 | + } | ||
| 530 | + }).then((res)=> { | ||
| 531 | + console.log(JSON.stringify(res)); | ||
| 532 | + this.initData() | ||
| 533 | + }).finally(()=>{ | ||
| 534 | + this.subStream = "" | ||
| 535 | + }) | ||
| 536 | + }).catch(() => { | ||
| 537 | + this.subStream = "" | ||
| 538 | + }); | ||
| 539 | + | ||
| 540 | + }, | ||
| 541 | + channelSubStreamChange: function (row) { | ||
| 542 | + this.$axios({ | ||
| 543 | + method: 'post', | ||
| 544 | + url: `/api/device/query/channel/stream/identification/update/`, | ||
| 545 | + params: { | ||
| 546 | + deviceId: this.deviceId, | ||
| 547 | + channelId: row.channelId, | ||
| 548 | + streamIdentification: row.streamIdentification | ||
| 549 | + } | ||
| 550 | + }).then(function (res) { | ||
| 551 | + console.log(JSON.stringify(res)); | ||
| 552 | + }); | ||
| 553 | + }, | ||
| 498 | refresh: function () { | 554 | refresh: function () { |
| 499 | this.initData(); | 555 | this.initData(); |
| 500 | }, | 556 | }, |
web_src/src/components/dialog/deviceEdit.vue
| @@ -61,12 +61,6 @@ | @@ -61,12 +61,6 @@ | ||
| 61 | <el-form-item v-if="form.subscribeCycleForMobilePosition > 0" label="移动位置报送间隔" prop="subscribeCycleForCatalog" > | 61 | <el-form-item v-if="form.subscribeCycleForMobilePosition > 0" label="移动位置报送间隔" prop="subscribeCycleForCatalog" > |
| 62 | <el-input v-model="form.mobilePositionSubmissionInterval" clearable ></el-input> | 62 | <el-input v-model="form.mobilePositionSubmissionInterval" clearable ></el-input> |
| 63 | </el-form-item> | 63 | </el-form-item> |
| 64 | - <el-form-item label="主子码流开关" prop="switchPrimarySubStream" > | ||
| 65 | - <el-select v-model="form.switchPrimarySubStream" style="float: left; width: 100%" > | ||
| 66 | - <el-option key="true" label="开启" :value="true"></el-option> | ||
| 67 | - <el-option key="false" label="关闭" :value="false"></el-option> | ||
| 68 | - </el-select> | ||
| 69 | - </el-form-item> | ||
| 70 | <el-form-item label="其他选项"> | 64 | <el-form-item label="其他选项"> |
| 71 | <el-checkbox label="SSRC校验" v-model="form.ssrcCheck" style="float: left"></el-checkbox> | 65 | <el-checkbox label="SSRC校验" v-model="form.ssrcCheck" style="float: left"></el-checkbox> |
| 72 | <el-checkbox label="作为消息通道" v-model="form.asMessageChannel" style="float: left"></el-checkbox> | 66 | <el-checkbox label="作为消息通道" v-model="form.asMessageChannel" style="float: left"></el-checkbox> |
数据库/2.7.0/初始化-mysql-2.7.0.sql
0 → 100644
| 1 | +/*建表*/ | ||
| 2 | +create table wvp_device ( | ||
| 3 | + id serial primary key , | ||
| 4 | + device_id character varying(50) not null , | ||
| 5 | + name character varying(255), | ||
| 6 | + manufacturer character varying(255), | ||
| 7 | + model character varying(255), | ||
| 8 | + firmware character varying(255), | ||
| 9 | + transport character varying(50), | ||
| 10 | + stream_mode character varying(50), | ||
| 11 | + on_line bool default false, | ||
| 12 | + register_time character varying(50), | ||
| 13 | + keepalive_time character varying(50), | ||
| 14 | + ip character varying(50), | ||
| 15 | + create_time character varying(50), | ||
| 16 | + update_time character varying(50), | ||
| 17 | + port integer, | ||
| 18 | + expires integer, | ||
| 19 | + subscribe_cycle_for_catalog integer DEFAULT 0, | ||
| 20 | + subscribe_cycle_for_mobile_position integer DEFAULT 0, | ||
| 21 | + mobile_position_submission_interval integer DEFAULT 5, | ||
| 22 | + subscribe_cycle_for_alarm integer DEFAULT 0, | ||
| 23 | + host_address character varying(50), | ||
| 24 | + charset character varying(50), | ||
| 25 | + ssrc_check bool default false, | ||
| 26 | + geo_coord_sys character varying(50), | ||
| 27 | + media_server_id character varying(50), | ||
| 28 | + custom_name character varying(255), | ||
| 29 | + sdp_ip character varying(50), | ||
| 30 | + local_ip character varying(50), | ||
| 31 | + password character varying(255), | ||
| 32 | + as_message_channel bool default false, | ||
| 33 | + keepalive_interval_time integer, | ||
| 34 | + switch_primary_sub_stream bool default false, | ||
| 35 | + broadcast_push_after_ack bool default false, | ||
| 36 | + constraint uk_device_device unique (device_id) | ||
| 37 | +); | ||
| 38 | + | ||
| 39 | +create table wvp_device_alarm ( | ||
| 40 | + id serial primary key , | ||
| 41 | + device_id character varying(50) not null, | ||
| 42 | + channel_id character varying(50) not null, | ||
| 43 | + alarm_priority character varying(50), | ||
| 44 | + alarm_method character varying(50), | ||
| 45 | + alarm_time character varying(50), | ||
| 46 | + alarm_description character varying(255), | ||
| 47 | + longitude double precision, | ||
| 48 | + latitude double precision, | ||
| 49 | + alarm_type character varying(50), | ||
| 50 | + create_time character varying(50) not null | ||
| 51 | +); | ||
| 52 | + | ||
| 53 | +create table wvp_device_channel ( | ||
| 54 | + id serial primary key , | ||
| 55 | + channel_id character varying(50) not null, | ||
| 56 | + name character varying(255), | ||
| 57 | + custom_name character varying(255), | ||
| 58 | + manufacture character varying(50), | ||
| 59 | + model character varying(50), | ||
| 60 | + owner character varying(50), | ||
| 61 | + civil_code character varying(50), | ||
| 62 | + block character varying(50), | ||
| 63 | + address character varying(50), | ||
| 64 | + parent_id character varying(50), | ||
| 65 | + safety_way integer, | ||
| 66 | + register_way integer, | ||
| 67 | + cert_num character varying(50), | ||
| 68 | + certifiable integer, | ||
| 69 | + err_code integer, | ||
| 70 | + end_time character varying(50), | ||
| 71 | + secrecy character varying(50), | ||
| 72 | + ip_address character varying(50), | ||
| 73 | + port integer, | ||
| 74 | + password character varying(255), | ||
| 75 | + ptz_type integer, | ||
| 76 | + custom_ptz_type integer, | ||
| 77 | + status bool default false, | ||
| 78 | + longitude double precision, | ||
| 79 | + custom_longitude double precision, | ||
| 80 | + latitude double precision, | ||
| 81 | + custom_latitude double precision, | ||
| 82 | + stream_id character varying(255), | ||
| 83 | + device_id character varying(50) not null, | ||
| 84 | + parental character varying(50), | ||
| 85 | + has_audio bool default false, | ||
| 86 | + create_time character varying(50) not null, | ||
| 87 | + update_time character varying(50) not null, | ||
| 88 | + sub_count integer, | ||
| 89 | + longitude_gcj02 double precision, | ||
| 90 | + latitude_gcj02 double precision, | ||
| 91 | + longitude_wgs84 double precision, | ||
| 92 | + latitude_wgs84 double precision, | ||
| 93 | + business_group_id character varying(50), | ||
| 94 | + gps_time character varying(50), | ||
| 95 | + stream_identification character varying(50), | ||
| 96 | + constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id) | ||
| 97 | +); | ||
| 98 | + | ||
| 99 | +create table wvp_device_mobile_position ( | ||
| 100 | + id serial primary key, | ||
| 101 | + device_id character varying(50) not null, | ||
| 102 | + channel_id character varying(50) not null, | ||
| 103 | + device_name character varying(255), | ||
| 104 | + time character varying(50), | ||
| 105 | + longitude double precision, | ||
| 106 | + latitude double precision, | ||
| 107 | + altitude double precision, | ||
| 108 | + speed double precision, | ||
| 109 | + direction double precision, | ||
| 110 | + report_source character varying(50), | ||
| 111 | + longitude_gcj02 double precision, | ||
| 112 | + latitude_gcj02 double precision, | ||
| 113 | + longitude_wgs84 double precision, | ||
| 114 | + latitude_wgs84 double precision, | ||
| 115 | + create_time character varying(50) | ||
| 116 | +); | ||
| 117 | + | ||
| 118 | +create table wvp_gb_stream ( | ||
| 119 | + gb_stream_id serial primary key, | ||
| 120 | + app character varying(255) not null, | ||
| 121 | + stream character varying(255) not null, | ||
| 122 | + gb_id character varying(50) not null, | ||
| 123 | + name character varying(255), | ||
| 124 | + longitude double precision, | ||
| 125 | + latitude double precision, | ||
| 126 | + stream_type character varying(50), | ||
| 127 | + media_server_id character varying(50), | ||
| 128 | + create_time character varying(50), | ||
| 129 | + constraint uk_gb_stream_unique_gb_id unique (gb_id), | ||
| 130 | + constraint uk_gb_stream_unique_app_stream unique (app, stream) | ||
| 131 | +); | ||
| 132 | + | ||
| 133 | +create table wvp_log ( | ||
| 134 | + id serial primary key , | ||
| 135 | + name character varying(50), | ||
| 136 | + type character varying(50), | ||
| 137 | + uri character varying(200), | ||
| 138 | + address character varying(50), | ||
| 139 | + result character varying(50), | ||
| 140 | + timing bigint, | ||
| 141 | + username character varying(50), | ||
| 142 | + create_time character varying(50) | ||
| 143 | +); | ||
| 144 | + | ||
| 145 | +create table wvp_media_server ( | ||
| 146 | + id character varying(255) primary key , | ||
| 147 | + ip character varying(50), | ||
| 148 | + hook_ip character varying(50), | ||
| 149 | + sdp_ip character varying(50), | ||
| 150 | + stream_ip character varying(50), | ||
| 151 | + http_port integer, | ||
| 152 | + http_ssl_port integer, | ||
| 153 | + rtmp_port integer, | ||
| 154 | + rtmp_ssl_port integer, | ||
| 155 | + rtp_proxy_port integer, | ||
| 156 | + rtsp_port integer, | ||
| 157 | + rtsp_ssl_port integer, | ||
| 158 | + auto_config bool default false, | ||
| 159 | + secret character varying(50), | ||
| 160 | + rtp_enable bool default false, | ||
| 161 | + rtp_port_range character varying(50), | ||
| 162 | + send_rtp_port_range character varying(50), | ||
| 163 | + record_assist_port integer, | ||
| 164 | + default_server bool default false, | ||
| 165 | + create_time character varying(50), | ||
| 166 | + update_time character varying(50), | ||
| 167 | + hook_alive_interval integer, | ||
| 168 | + record_path character varying(255), | ||
| 169 | + record_day integer default 7, | ||
| 170 | + constraint uk_media_server_unique_ip_http_port unique (ip, http_port) | ||
| 171 | +); | ||
| 172 | + | ||
| 173 | +create table wvp_platform ( | ||
| 174 | + id serial primary key , | ||
| 175 | + enable bool default false, | ||
| 176 | + name character varying(255), | ||
| 177 | + server_gb_id character varying(50), | ||
| 178 | + server_gb_domain character varying(50), | ||
| 179 | + server_ip character varying(50), | ||
| 180 | + server_port integer, | ||
| 181 | + device_gb_id character varying(50), | ||
| 182 | + device_ip character varying(50), | ||
| 183 | + device_port character varying(50), | ||
| 184 | + username character varying(255), | ||
| 185 | + password character varying(50), | ||
| 186 | + expires character varying(50), | ||
| 187 | + keep_timeout character varying(50), | ||
| 188 | + transport character varying(50), | ||
| 189 | + character_set character varying(50), | ||
| 190 | + catalog_id character varying(50), | ||
| 191 | + ptz bool default false, | ||
| 192 | + rtcp bool default false, | ||
| 193 | + status bool default false, | ||
| 194 | + start_offline_push bool default false, | ||
| 195 | + administrative_division character varying(50), | ||
| 196 | + catalog_group integer, | ||
| 197 | + create_time character varying(50), | ||
| 198 | + update_time character varying(50), | ||
| 199 | + as_message_channel bool default false, | ||
| 200 | + auto_push_channel bool default false, | ||
| 201 | + constraint uk_platform_unique_server_gb_id unique (server_gb_id) | ||
| 202 | +); | ||
| 203 | + | ||
| 204 | +create table wvp_platform_catalog ( | ||
| 205 | + id character varying(50), | ||
| 206 | + platform_id character varying(50), | ||
| 207 | + name character varying(255), | ||
| 208 | + parent_id character varying(50), | ||
| 209 | + civil_code character varying(50), | ||
| 210 | + business_group_id character varying(50), | ||
| 211 | + constraint uk_platform_catalog_id_platform_id unique (id, platform_id) | ||
| 212 | +); | ||
| 213 | + | ||
| 214 | +create table wvp_platform_gb_channel ( | ||
| 215 | + id serial primary key , | ||
| 216 | + platform_id character varying(50), | ||
| 217 | + catalog_id character varying(50), | ||
| 218 | + device_channel_id integer, | ||
| 219 | + constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id) | ||
| 220 | +); | ||
| 221 | + | ||
| 222 | +create table wvp_platform_gb_stream ( | ||
| 223 | + id serial primary key, | ||
| 224 | + platform_id character varying(50), | ||
| 225 | + catalog_id character varying(50), | ||
| 226 | + gb_stream_id integer, | ||
| 227 | + constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id) | ||
| 228 | +); | ||
| 229 | + | ||
| 230 | +create table wvp_stream_proxy ( | ||
| 231 | + id serial primary key, | ||
| 232 | + type character varying(50), | ||
| 233 | + app character varying(255), | ||
| 234 | + stream character varying(255), | ||
| 235 | + url character varying(255), | ||
| 236 | + src_url character varying(255), | ||
| 237 | + dst_url character varying(255), | ||
| 238 | + timeout_ms integer, | ||
| 239 | + ffmpeg_cmd_key character varying(255), | ||
| 240 | + rtp_type character varying(50), | ||
| 241 | + media_server_id character varying(50), | ||
| 242 | + enable_audio bool default false, | ||
| 243 | + enable_mp4 bool default false, | ||
| 244 | + enable bool default false, | ||
| 245 | + status boolean, | ||
| 246 | + enable_remove_none_reader bool default false, | ||
| 247 | + create_time character varying(50), | ||
| 248 | + name character varying(255), | ||
| 249 | + update_time character varying(50), | ||
| 250 | + stream_key character varying(255), | ||
| 251 | + enable_disable_none_reader bool default false, | ||
| 252 | + constraint uk_stream_proxy_app_stream unique (app, stream) | ||
| 253 | +); | ||
| 254 | + | ||
| 255 | +create table wvp_stream_push ( | ||
| 256 | + id serial primary key, | ||
| 257 | + app character varying(255), | ||
| 258 | + stream character varying(255), | ||
| 259 | + total_reader_count character varying(50), | ||
| 260 | + origin_type integer, | ||
| 261 | + origin_type_str character varying(50), | ||
| 262 | + create_time character varying(50), | ||
| 263 | + alive_second integer, | ||
| 264 | + media_server_id character varying(50), | ||
| 265 | + server_id character varying(50), | ||
| 266 | + push_time character varying(50), | ||
| 267 | + status bool default false, | ||
| 268 | + update_time character varying(50), | ||
| 269 | + push_ing bool default false, | ||
| 270 | + self bool default false, | ||
| 271 | + constraint uk_stream_push_app_stream unique (app, stream) | ||
| 272 | +); | ||
| 273 | +create table wvp_cloud_record ( | ||
| 274 | + id serial primary key, | ||
| 275 | + app character varying(255), | ||
| 276 | + stream character varying(255), | ||
| 277 | + call_id character varying(255), | ||
| 278 | + start_time bigint, | ||
| 279 | + end_time bigint, | ||
| 280 | + media_server_id character varying(50), | ||
| 281 | + file_name character varying(255), | ||
| 282 | + folder character varying(255), | ||
| 283 | + file_path character varying(255), | ||
| 284 | + collect bool default false, | ||
| 285 | + file_size bigint, | ||
| 286 | + time_len bigint, | ||
| 287 | + constraint uk_stream_push_app_stream_path unique (app, stream, file_path) | ||
| 288 | +); | ||
| 289 | + | ||
| 290 | +create table wvp_user ( | ||
| 291 | + id serial primary key, | ||
| 292 | + username character varying(255), | ||
| 293 | + password character varying(255), | ||
| 294 | + role_id integer, | ||
| 295 | + create_time character varying(50), | ||
| 296 | + update_time character varying(50), | ||
| 297 | + push_key character varying(50), | ||
| 298 | + constraint uk_user_username unique (username) | ||
| 299 | +); | ||
| 300 | + | ||
| 301 | +create table wvp_user_role ( | ||
| 302 | + id serial primary key, | ||
| 303 | + name character varying(50), | ||
| 304 | + authority character varying(50), | ||
| 305 | + create_time character varying(50), | ||
| 306 | + update_time character varying(50) | ||
| 307 | +); | ||
| 308 | +create table wvp_resources_tree ( | ||
| 309 | + id serial primary key , | ||
| 310 | + is_catalog bool default true, | ||
| 311 | + device_channel_id integer , | ||
| 312 | + gb_stream_id integer, | ||
| 313 | + name character varying(255), | ||
| 314 | + parentId integer, | ||
| 315 | + path character varying(255) | ||
| 316 | +); | ||
| 317 | + | ||
| 318 | + | ||
| 319 | +/*初始数据*/ | ||
| 320 | +INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3'); | ||
| 321 | +INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57'); | ||
| 322 | + | ||
| 323 | + | ||
| 324 | + |
数据库/2.7.0/初始化-postgresql-kingbase-2.7.0.sql
0 → 100644
| 1 | +/*建表*/ | ||
| 2 | +create table wvp_device ( | ||
| 3 | + id serial primary key , | ||
| 4 | + device_id character varying(50) not null , | ||
| 5 | + name character varying(255), | ||
| 6 | + manufacturer character varying(255), | ||
| 7 | + model character varying(255), | ||
| 8 | + firmware character varying(255), | ||
| 9 | + transport character varying(50), | ||
| 10 | + stream_mode character varying(50), | ||
| 11 | + on_line bool default false, | ||
| 12 | + register_time character varying(50), | ||
| 13 | + keepalive_time character varying(50), | ||
| 14 | + ip character varying(50), | ||
| 15 | + create_time character varying(50), | ||
| 16 | + update_time character varying(50), | ||
| 17 | + port integer, | ||
| 18 | + expires integer, | ||
| 19 | + subscribe_cycle_for_catalog integer DEFAULT 0, | ||
| 20 | + subscribe_cycle_for_mobile_position integer DEFAULT 0, | ||
| 21 | + mobile_position_submission_interval integer DEFAULT 5, | ||
| 22 | + subscribe_cycle_for_alarm integer DEFAULT 0, | ||
| 23 | + host_address character varying(50), | ||
| 24 | + charset character varying(50), | ||
| 25 | + ssrc_check bool default false, | ||
| 26 | + geo_coord_sys character varying(50), | ||
| 27 | + media_server_id character varying(50), | ||
| 28 | + custom_name character varying(255), | ||
| 29 | + sdp_ip character varying(50), | ||
| 30 | + local_ip character varying(50), | ||
| 31 | + password character varying(255), | ||
| 32 | + as_message_channel bool default false, | ||
| 33 | + keepalive_interval_time integer, | ||
| 34 | + switch_primary_sub_stream bool default false, | ||
| 35 | + broadcast_push_after_ack bool default false, | ||
| 36 | + constraint uk_device_device unique (device_id) | ||
| 37 | +); | ||
| 38 | + | ||
| 39 | +create table wvp_device_alarm ( | ||
| 40 | + id serial primary key , | ||
| 41 | + device_id character varying(50) not null, | ||
| 42 | + channel_id character varying(50) not null, | ||
| 43 | + alarm_priority character varying(50), | ||
| 44 | + alarm_method character varying(50), | ||
| 45 | + alarm_time character varying(50), | ||
| 46 | + alarm_description character varying(255), | ||
| 47 | + longitude double precision, | ||
| 48 | + latitude double precision, | ||
| 49 | + alarm_type character varying(50), | ||
| 50 | + create_time character varying(50) not null | ||
| 51 | +); | ||
| 52 | + | ||
| 53 | +create table wvp_device_channel ( | ||
| 54 | + id serial primary key , | ||
| 55 | + channel_id character varying(50) not null, | ||
| 56 | + name character varying(255), | ||
| 57 | + custom_name character varying(255), | ||
| 58 | + manufacture character varying(50), | ||
| 59 | + model character varying(50), | ||
| 60 | + owner character varying(50), | ||
| 61 | + civil_code character varying(50), | ||
| 62 | + block character varying(50), | ||
| 63 | + address character varying(50), | ||
| 64 | + parent_id character varying(50), | ||
| 65 | + safety_way integer, | ||
| 66 | + register_way integer, | ||
| 67 | + cert_num character varying(50), | ||
| 68 | + certifiable integer, | ||
| 69 | + err_code integer, | ||
| 70 | + end_time character varying(50), | ||
| 71 | + secrecy character varying(50), | ||
| 72 | + ip_address character varying(50), | ||
| 73 | + port integer, | ||
| 74 | + password character varying(255), | ||
| 75 | + ptz_type integer, | ||
| 76 | + custom_ptz_type integer, | ||
| 77 | + status bool default false, | ||
| 78 | + longitude double precision, | ||
| 79 | + custom_longitude double precision, | ||
| 80 | + latitude double precision, | ||
| 81 | + custom_latitude double precision, | ||
| 82 | + stream_id character varying(255), | ||
| 83 | + device_id character varying(50) not null, | ||
| 84 | + parental character varying(50), | ||
| 85 | + has_audio bool default false, | ||
| 86 | + create_time character varying(50) not null, | ||
| 87 | + update_time character varying(50) not null, | ||
| 88 | + sub_count integer, | ||
| 89 | + longitude_gcj02 double precision, | ||
| 90 | + latitude_gcj02 double precision, | ||
| 91 | + longitude_wgs84 double precision, | ||
| 92 | + latitude_wgs84 double precision, | ||
| 93 | + business_group_id character varying(50), | ||
| 94 | + gps_time character varying(50), | ||
| 95 | + stream_identification character varying(50), | ||
| 96 | + constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id) | ||
| 97 | +); | ||
| 98 | + | ||
| 99 | +create table wvp_device_mobile_position ( | ||
| 100 | + id serial primary key, | ||
| 101 | + device_id character varying(50) not null, | ||
| 102 | + channel_id character varying(50) not null, | ||
| 103 | + device_name character varying(255), | ||
| 104 | + time character varying(50), | ||
| 105 | + longitude double precision, | ||
| 106 | + latitude double precision, | ||
| 107 | + altitude double precision, | ||
| 108 | + speed double precision, | ||
| 109 | + direction double precision, | ||
| 110 | + report_source character varying(50), | ||
| 111 | + longitude_gcj02 double precision, | ||
| 112 | + latitude_gcj02 double precision, | ||
| 113 | + longitude_wgs84 double precision, | ||
| 114 | + latitude_wgs84 double precision, | ||
| 115 | + create_time character varying(50) | ||
| 116 | +); | ||
| 117 | + | ||
| 118 | +create table wvp_gb_stream ( | ||
| 119 | + gb_stream_id serial primary key, | ||
| 120 | + app character varying(255) not null, | ||
| 121 | + stream character varying(255) not null, | ||
| 122 | + gb_id character varying(50) not null, | ||
| 123 | + name character varying(255), | ||
| 124 | + longitude double precision, | ||
| 125 | + latitude double precision, | ||
| 126 | + stream_type character varying(50), | ||
| 127 | + media_server_id character varying(50), | ||
| 128 | + create_time character varying(50), | ||
| 129 | + constraint uk_gb_stream_unique_gb_id unique (gb_id), | ||
| 130 | + constraint uk_gb_stream_unique_app_stream unique (app, stream) | ||
| 131 | +); | ||
| 132 | + | ||
| 133 | +create table wvp_log ( | ||
| 134 | + id serial primary key , | ||
| 135 | + name character varying(50), | ||
| 136 | + type character varying(50), | ||
| 137 | + uri character varying(200), | ||
| 138 | + address character varying(50), | ||
| 139 | + result character varying(50), | ||
| 140 | + timing bigint, | ||
| 141 | + username character varying(50), | ||
| 142 | + create_time character varying(50) | ||
| 143 | +); | ||
| 144 | + | ||
| 145 | +create table wvp_media_server ( | ||
| 146 | + id character varying(255) primary key , | ||
| 147 | + ip character varying(50), | ||
| 148 | + hook_ip character varying(50), | ||
| 149 | + sdp_ip character varying(50), | ||
| 150 | + stream_ip character varying(50), | ||
| 151 | + http_port integer, | ||
| 152 | + http_ssl_port integer, | ||
| 153 | + rtmp_port integer, | ||
| 154 | + rtmp_ssl_port integer, | ||
| 155 | + rtp_proxy_port integer, | ||
| 156 | + rtsp_port integer, | ||
| 157 | + rtsp_ssl_port integer, | ||
| 158 | + auto_config bool default false, | ||
| 159 | + secret character varying(50), | ||
| 160 | + rtp_enable bool default false, | ||
| 161 | + rtp_port_range character varying(50), | ||
| 162 | + send_rtp_port_range character varying(50), | ||
| 163 | + record_assist_port integer, | ||
| 164 | + default_server bool default false, | ||
| 165 | + create_time character varying(50), | ||
| 166 | + update_time character varying(50), | ||
| 167 | + hook_alive_interval integer, | ||
| 168 | + record_path character varying(255), | ||
| 169 | + record_day integer default 7, | ||
| 170 | + constraint uk_media_server_unique_ip_http_port unique (ip, http_port) | ||
| 171 | +); | ||
| 172 | + | ||
| 173 | +create table wvp_platform ( | ||
| 174 | + id serial primary key , | ||
| 175 | + enable bool default false, | ||
| 176 | + name character varying(255), | ||
| 177 | + server_gb_id character varying(50), | ||
| 178 | + server_gb_domain character varying(50), | ||
| 179 | + server_ip character varying(50), | ||
| 180 | + server_port integer, | ||
| 181 | + device_gb_id character varying(50), | ||
| 182 | + device_ip character varying(50), | ||
| 183 | + device_port character varying(50), | ||
| 184 | + username character varying(255), | ||
| 185 | + password character varying(50), | ||
| 186 | + expires character varying(50), | ||
| 187 | + keep_timeout character varying(50), | ||
| 188 | + transport character varying(50), | ||
| 189 | + character_set character varying(50), | ||
| 190 | + catalog_id character varying(50), | ||
| 191 | + ptz bool default false, | ||
| 192 | + rtcp bool default false, | ||
| 193 | + status bool default false, | ||
| 194 | + start_offline_push bool default false, | ||
| 195 | + administrative_division character varying(50), | ||
| 196 | + catalog_group integer, | ||
| 197 | + create_time character varying(50), | ||
| 198 | + update_time character varying(50), | ||
| 199 | + as_message_channel bool default false, | ||
| 200 | + auto_push_channel bool default false, | ||
| 201 | + constraint uk_platform_unique_server_gb_id unique (server_gb_id) | ||
| 202 | +); | ||
| 203 | + | ||
| 204 | +create table wvp_platform_catalog ( | ||
| 205 | + id character varying(50), | ||
| 206 | + platform_id character varying(50), | ||
| 207 | + name character varying(255), | ||
| 208 | + parent_id character varying(50), | ||
| 209 | + civil_code character varying(50), | ||
| 210 | + business_group_id character varying(50), | ||
| 211 | + constraint uk_platform_catalog_id_platform_id unique (id, platform_id) | ||
| 212 | +); | ||
| 213 | + | ||
| 214 | +create table wvp_platform_gb_channel ( | ||
| 215 | + id serial primary key , | ||
| 216 | + platform_id character varying(50), | ||
| 217 | + catalog_id character varying(50), | ||
| 218 | + device_channel_id integer, | ||
| 219 | + constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id) | ||
| 220 | +); | ||
| 221 | + | ||
| 222 | +create table wvp_platform_gb_stream ( | ||
| 223 | + id serial primary key, | ||
| 224 | + platform_id character varying(50), | ||
| 225 | + catalog_id character varying(50), | ||
| 226 | + gb_stream_id integer, | ||
| 227 | + constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id) | ||
| 228 | +); | ||
| 229 | + | ||
| 230 | +create table wvp_stream_proxy ( | ||
| 231 | + id serial primary key, | ||
| 232 | + type character varying(50), | ||
| 233 | + app character varying(255), | ||
| 234 | + stream character varying(255), | ||
| 235 | + url character varying(255), | ||
| 236 | + src_url character varying(255), | ||
| 237 | + dst_url character varying(255), | ||
| 238 | + timeout_ms integer, | ||
| 239 | + ffmpeg_cmd_key character varying(255), | ||
| 240 | + rtp_type character varying(50), | ||
| 241 | + media_server_id character varying(50), | ||
| 242 | + enable_audio bool default false, | ||
| 243 | + enable_mp4 bool default false, | ||
| 244 | + enable bool default false, | ||
| 245 | + status boolean, | ||
| 246 | + enable_remove_none_reader bool default false, | ||
| 247 | + create_time character varying(50), | ||
| 248 | + name character varying(255), | ||
| 249 | + update_time character varying(50), | ||
| 250 | + stream_key character varying(255), | ||
| 251 | + enable_disable_none_reader bool default false, | ||
| 252 | + constraint uk_stream_proxy_app_stream unique (app, stream) | ||
| 253 | +); | ||
| 254 | + | ||
| 255 | +create table wvp_stream_push ( | ||
| 256 | + id serial primary key, | ||
| 257 | + app character varying(255), | ||
| 258 | + stream character varying(255), | ||
| 259 | + total_reader_count character varying(50), | ||
| 260 | + origin_type integer, | ||
| 261 | + origin_type_str character varying(50), | ||
| 262 | + create_time character varying(50), | ||
| 263 | + alive_second integer, | ||
| 264 | + media_server_id character varying(50), | ||
| 265 | + server_id character varying(50), | ||
| 266 | + push_time character varying(50), | ||
| 267 | + status bool default false, | ||
| 268 | + update_time character varying(50), | ||
| 269 | + push_ing bool default false, | ||
| 270 | + self bool default false, | ||
| 271 | + constraint uk_stream_push_app_stream unique (app, stream) | ||
| 272 | +); | ||
| 273 | +create table wvp_cloud_record ( | ||
| 274 | + id serial primary key, | ||
| 275 | + app character varying(255), | ||
| 276 | + stream character varying(255), | ||
| 277 | + call_id character varying(255), | ||
| 278 | + start_time int8, | ||
| 279 | + end_time int8, | ||
| 280 | + media_server_id character varying(50), | ||
| 281 | + file_name character varying(255), | ||
| 282 | + folder character varying(255), | ||
| 283 | + file_path character varying(255), | ||
| 284 | + collect bool default false, | ||
| 285 | + file_size int8, | ||
| 286 | + time_len int8, | ||
| 287 | + constraint uk_stream_push_app_stream_path unique (app, stream, file_path) | ||
| 288 | +); | ||
| 289 | + | ||
| 290 | +create table wvp_user ( | ||
| 291 | + id serial primary key, | ||
| 292 | + username character varying(255), | ||
| 293 | + password character varying(255), | ||
| 294 | + role_id integer, | ||
| 295 | + create_time character varying(50), | ||
| 296 | + update_time character varying(50), | ||
| 297 | + push_key character varying(50), | ||
| 298 | + constraint uk_user_username unique (username) | ||
| 299 | +); | ||
| 300 | + | ||
| 301 | +create table wvp_user_role ( | ||
| 302 | + id serial primary key, | ||
| 303 | + name character varying(50), | ||
| 304 | + authority character varying(50), | ||
| 305 | + create_time character varying(50), | ||
| 306 | + update_time character varying(50) | ||
| 307 | +); | ||
| 308 | +create table wvp_resources_tree ( | ||
| 309 | + id serial primary key , | ||
| 310 | + is_catalog bool default true, | ||
| 311 | + device_channel_id integer , | ||
| 312 | + gb_stream_id integer, | ||
| 313 | + name character varying(255), | ||
| 314 | + parentId integer, | ||
| 315 | + path character varying(255) | ||
| 316 | +); | ||
| 317 | + | ||
| 318 | + | ||
| 319 | +/*初始数据*/ | ||
| 320 | +INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3'); | ||
| 321 | +INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57'); | ||
| 322 | + | ||
| 323 | + | ||
| 324 | + |
数据库/2.7.0/更新-mysql-2.7.0.sql
0 → 100644