Просмотр исходного кода

拆分redis中device与channel的存储方式
支持分页
接口直接返回播放地址

648540858 5 лет назад
Родитель
Сommit
da14c7f24c
21 измененных файлов с 1445 добавлено и 78 удалено
  1. 11 0
      pom.xml
  2. 44 0
      src/main/java/com/genersoft/iot/vmp/common/PageResult.java
  3. 59 0
      src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
  4. 8 2
      src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
  5. 667 0
      src/main/java/com/genersoft/iot/vmp/conf/MediaServerConfig.java
  6. 18 8
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
  7. 27 1
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
  8. 2 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
  9. 31 5
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  10. 9 12
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
  11. 1 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
  12. 43 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/SolrProxyServletConfiguration.java
  13. 15 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
  14. 93 4
      src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
  15. 58 10
      src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
  16. 166 16
      src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
  17. 116 0
      src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
  18. 21 3
      src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
  19. 5 4
      src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
  20. 30 0
      src/main/java/com/genersoft/iot/vmp/web/AuthController.java
  21. 21 11
      src/main/resources/application.yml

+ 11 - 0
pom.xml

@@ -143,6 +143,17 @@
 			<artifactId>jedis</artifactId>
 			<version>2.9.0</version>
 		</dependency>
+
+		<dependency>
+			<groupId>org.mitre.dsmiley.httpproxy</groupId>
+			<artifactId>smiley-http-proxy-servlet</artifactId>
+			<version>1.7</version>
+		</dependency>
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+			<version>18.0</version>
+		</dependency>
 		
 	</dependencies>
 	

+ 44 - 0
src/main/java/com/genersoft/iot/vmp/common/PageResult.java

@@ -0,0 +1,44 @@
+package com.genersoft.iot.vmp.common;
+
+import java.util.List;
+
+public class PageResult<T> {
+
+    private int page;
+    private int count;
+    private int total;
+
+    private List<T> data;
+
+    public List<T> getData() {
+        return data;
+    }
+
+    public void setData(List<T> data) {
+        this.data = data;
+    }
+
+    public int getPage() {
+        return page;
+    }
+
+    public void setPage(int page) {
+        this.page = page;
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    public void setCount(int count) {
+        this.count = count;
+    }
+
+    public int getTotal() {
+        return total;
+    }
+
+    public void setTotal(int total) {
+        this.total = total;
+    }
+}

+ 59 - 0
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java

@@ -0,0 +1,59 @@
+package com.genersoft.iot.vmp.common;
+
+public class StreamInfo {
+
+    private String ssrc;
+    private String flv;
+    private String WS_FLV;
+    private String RTMP;
+    private String HLS;
+    private String RTSP;
+
+    public String getSsrc() {
+        return ssrc;
+    }
+
+    public void setSsrc(String ssrc) {
+        this.ssrc = ssrc;
+    }
+
+    public String getFlv() {
+        return flv;
+    }
+
+    public void setFlv(String flv) {
+        this.flv = flv;
+    }
+
+    public String getWS_FLV() {
+        return WS_FLV;
+    }
+
+    public void setWS_FLV(String WS_FLV) {
+        this.WS_FLV = WS_FLV;
+    }
+
+    public String getRTMP() {
+        return RTMP;
+    }
+
+    public void setRTMP(String RTMP) {
+        this.RTMP = RTMP;
+    }
+
+    public String getHLS() {
+        return HLS;
+    }
+
+    public void setHLS(String HLS) {
+        this.HLS = HLS;
+    }
+
+    public String getRTSP() {
+        return RTSP;
+    }
+
+    public void setRTSP(String RTSP) {
+        this.RTSP = RTSP;
+    }
+}

+ 8 - 2
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java

@@ -8,10 +8,16 @@ package com.genersoft.iot.vmp.common;
  */
 public class VideoManagerConstants {
 	
-	public static final String CACHEKEY_PREFIX = "VMP_deviceId_";
+	public static final String MEDIA_SERVER_PREFIX = "VMP_media_server";
+
+	public static final String DEVICE_PREFIX = "VMP_device_";
+
+	public static final String CACHEKEY_PREFIX = "VMP_channel_";
 
 	public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_";
-	
+
+	public static final String PLAYER_PREFIX = "VMP_player_";
+
 	public static final String EVENT_ONLINE_REGISTER = "1";
 	
 	public static final String EVENT_ONLINE_KEEPLIVE = "2";

+ 667 - 0
src/main/java/com/genersoft/iot/vmp/conf/MediaServerConfig.java

@@ -0,0 +1,667 @@
+package com.genersoft.iot.vmp.conf;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+public class MediaServerConfig {
+
+    @JSONField(name = "api.apiDebug")
+    private String apiDebug;
+
+    @JSONField(name = "api.secret")
+    private String apiSecret;
+
+    @JSONField(name = "ffmpeg.bin")
+    private String ffmpegBin;
+
+    @JSONField(name = "ffmpeg.cmd")
+    private String ffmpegCmd;
+
+    @JSONField(name = "ffmpeg.log")
+    private String ffmpegLog;
+
+    @JSONField(name = "general.enableVhost")
+    private String generalEnableVhost;
+
+    @JSONField(name = "general.flowThreshold")
+    private String generalFlowThreshold;
+
+    @JSONField(name = "general.maxStreamWaitMS")
+    private String generalMaxStreamWaitMS;
+
+    @JSONField(name = "general.streamNoneReaderDelayMS")
+    private String generalStreamNoneReaderDelayMS;
+
+    @JSONField(name = "hls.fileBufSize")
+    private String hlsFileBufSize;
+
+    @JSONField(name = "hls.filePath")
+    private String hlsFilePath;
+
+    @JSONField(name = "hls.segDur")
+    private String hlsSegDur;
+
+    @JSONField(name = "hls.segNum")
+    private String hlsSegNum;
+
+    @JSONField(name = "hook.access_file_except_hls")
+    private String hookAccessFileExceptHLS;
+
+    @JSONField(name = "hook.admin_params")
+    private String hookAdminParams;
+
+    @JSONField(name = "hook.enable")
+    private String hookEnable;
+
+    @JSONField(name = "hook.on_flow_report")
+    private String hookOnFlowReport;
+
+    @JSONField(name = "hook.on_http_access")
+    private String hookOnHttpAccess;
+
+    @JSONField(name = "hook.on_play")
+    private String hookOnPlay;
+
+    @JSONField(name = "hook.on_publish")
+    private String hookOnPublish;
+
+    @JSONField(name = "hook.on_record_mp4")
+    private String hookOnRecordMp4;
+
+    @JSONField(name = "hook.on_rtsp_auth")
+    private String hookOnRtspAuth;
+
+    @JSONField(name = "hook.on_rtsp_realm")
+    private String hookOnRtspRealm;
+
+    @JSONField(name = "hook.on_shell_login")
+    private String hookOnShellLogin;
+
+    @JSONField(name = "hook.on_stream_changed")
+    private String hookOnStreamChanged;
+
+    @JSONField(name = "hook.on_stream_none_reader")
+    private String hookOnStreamNoneReader;
+
+    @JSONField(name = "hook.on_stream_not_found")
+    private String hookOnStreamNotFound;
+
+    @JSONField(name = "hook.timeoutSec")
+    private String hookTimeoutSec;
+
+    @JSONField(name = "http.charSet")
+    private String httpCharSet;
+
+    @JSONField(name = "http.keepAliveSecond")
+    private String httpKeepAliveSecond;
+
+    @JSONField(name = "http.maxReqCount")
+    private String httpMaxReqCount;
+
+    @JSONField(name = "http.maxReqSize")
+    private String httpMaxReqSize;
+
+    @JSONField(name = "http.notFound")
+    private String httpNotFound;
+
+    @JSONField(name = "http.port")
+    private String httpPort;
+
+    @JSONField(name = "http.rootPath")
+    private String httpRootPath;
+
+    @JSONField(name = "http.sendBufSize")
+    private String httpSendBufSize;
+
+    @JSONField(name = "http.sslport")
+    private String httpSSLport;
+
+    @JSONField(name = "multicast.addrMax")
+    private String multicastAddrMax;
+
+    @JSONField(name = "multicast.addrMin")
+    private String multicastAddrMin;
+
+    @JSONField(name = "multicast.udpTTL")
+    private String multicastUdpTTL;
+
+    @JSONField(name = "record.appName")
+    private String recordAppName;
+
+    @JSONField(name = "record.filePath")
+    private String recordFilePath;
+
+    @JSONField(name = "record.fileSecond")
+    private String recordFileSecond;
+
+    @JSONField(name = "record.sampleMS")
+    private String recordFileSampleMS;
+
+    @JSONField(name = "rtmp.handshakeSecond")
+    private String rtmpHandshakeSecond;
+
+    @JSONField(name = "rtmp.keepAliveSecond")
+    private String rtmpKeepAliveSecond;
+
+    @JSONField(name = "rtmp.modifyStamp")
+    private String rtmpModifyStamp;
+
+    @JSONField(name = "rtmp.port")
+    private String rtmpPort;
+
+    @JSONField(name = "rtp.audioMtuSize")
+    private String rtpAudioMtuSize;
+
+    @JSONField(name = "rtp.clearCount")
+    private String rtpClearCount;
+
+    @JSONField(name = "rtp.cycleMS")
+    private String rtpCycleMS;
+
+    @JSONField(name = "rtp.maxRtpCount")
+    private String rtpMaxRtpCount;
+
+    @JSONField(name = "rtp.videoMtuSize")
+    private String rtpVideoMtuSize;
+
+    @JSONField(name = "rtsp.authBasic")
+    private String rtspAuthBasic;
+
+    @JSONField(name = "rtsp.handshakeSecond")
+    private String rtspHandshakeSecond;
+
+    @JSONField(name = "rtsp.keepAliveSecond")
+    private String rtspKeepAliveSecond;
+
+    @JSONField(name = "rtsp.port")
+    private String rtspPort;
+
+    @JSONField(name = "rtsp.sslport")
+    private String rtspSSlport;
+
+    @JSONField(name = "shell.maxReqSize")
+    private String shellMaxReqSize;
+
+    @JSONField(name = "shell.shell")
+    private String shellPhell;
+
+
+    public String getApiDebug() {
+        return apiDebug;
+    }
+
+    public void setApiDebug(String apiDebug) {
+        this.apiDebug = apiDebug;
+    }
+
+    public String getApiSecret() {
+        return apiSecret;
+    }
+
+    public void setApiSecret(String apiSecret) {
+        this.apiSecret = apiSecret;
+    }
+
+    public String getFfmpegBin() {
+        return ffmpegBin;
+    }
+
+    public void setFfmpegBin(String ffmpegBin) {
+        this.ffmpegBin = ffmpegBin;
+    }
+
+    public String getFfmpegCmd() {
+        return ffmpegCmd;
+    }
+
+    public void setFfmpegCmd(String ffmpegCmd) {
+        this.ffmpegCmd = ffmpegCmd;
+    }
+
+    public String getFfmpegLog() {
+        return ffmpegLog;
+    }
+
+    public void setFfmpegLog(String ffmpegLog) {
+        this.ffmpegLog = ffmpegLog;
+    }
+
+    public String getGeneralEnableVhost() {
+        return generalEnableVhost;
+    }
+
+    public void setGeneralEnableVhost(String generalEnableVhost) {
+        this.generalEnableVhost = generalEnableVhost;
+    }
+
+    public String getGeneralFlowThreshold() {
+        return generalFlowThreshold;
+    }
+
+    public void setGeneralFlowThreshold(String generalFlowThreshold) {
+        this.generalFlowThreshold = generalFlowThreshold;
+    }
+
+    public String getGeneralMaxStreamWaitMS() {
+        return generalMaxStreamWaitMS;
+    }
+
+    public void setGeneralMaxStreamWaitMS(String generalMaxStreamWaitMS) {
+        this.generalMaxStreamWaitMS = generalMaxStreamWaitMS;
+    }
+
+    public String getGeneralStreamNoneReaderDelayMS() {
+        return generalStreamNoneReaderDelayMS;
+    }
+
+    public void setGeneralStreamNoneReaderDelayMS(String generalStreamNoneReaderDelayMS) {
+        this.generalStreamNoneReaderDelayMS = generalStreamNoneReaderDelayMS;
+    }
+
+    public String getHlsFileBufSize() {
+        return hlsFileBufSize;
+    }
+
+    public void setHlsFileBufSize(String hlsFileBufSize) {
+        this.hlsFileBufSize = hlsFileBufSize;
+    }
+
+    public String getHlsFilePath() {
+        return hlsFilePath;
+    }
+
+    public void setHlsFilePath(String hlsFilePath) {
+        this.hlsFilePath = hlsFilePath;
+    }
+
+    public String getHlsSegDur() {
+        return hlsSegDur;
+    }
+
+    public void setHlsSegDur(String hlsSegDur) {
+        this.hlsSegDur = hlsSegDur;
+    }
+
+    public String getHlsSegNum() {
+        return hlsSegNum;
+    }
+
+    public void setHlsSegNum(String hlsSegNum) {
+        this.hlsSegNum = hlsSegNum;
+    }
+
+    public String getHookAccessFileExceptHLS() {
+        return hookAccessFileExceptHLS;
+    }
+
+    public void setHookAccessFileExceptHLS(String hookAccessFileExceptHLS) {
+        this.hookAccessFileExceptHLS = hookAccessFileExceptHLS;
+    }
+
+    public String getHookAdminParams() {
+        return hookAdminParams;
+    }
+
+    public void setHookAdminParams(String hookAdminParams) {
+        this.hookAdminParams = hookAdminParams;
+    }
+
+    public String getHookEnable() {
+        return hookEnable;
+    }
+
+    public void setHookEnable(String hookEnable) {
+        this.hookEnable = hookEnable;
+    }
+
+    public String getHookOnFlowReport() {
+        return hookOnFlowReport;
+    }
+
+    public void setHookOnFlowReport(String hookOnFlowReport) {
+        this.hookOnFlowReport = hookOnFlowReport;
+    }
+
+    public String getHookOnHttpAccess() {
+        return hookOnHttpAccess;
+    }
+
+    public void setHookOnHttpAccess(String hookOnHttpAccess) {
+        this.hookOnHttpAccess = hookOnHttpAccess;
+    }
+
+    public String getHookOnPlay() {
+        return hookOnPlay;
+    }
+
+    public void setHookOnPlay(String hookOnPlay) {
+        this.hookOnPlay = hookOnPlay;
+    }
+
+    public String getHookOnPublish() {
+        return hookOnPublish;
+    }
+
+    public void setHookOnPublish(String hookOnPublish) {
+        this.hookOnPublish = hookOnPublish;
+    }
+
+    public String getHookOnRecordMp4() {
+        return hookOnRecordMp4;
+    }
+
+    public void setHookOnRecordMp4(String hookOnRecordMp4) {
+        this.hookOnRecordMp4 = hookOnRecordMp4;
+    }
+
+    public String getHookOnRtspAuth() {
+        return hookOnRtspAuth;
+    }
+
+    public void setHookOnRtspAuth(String hookOnRtspAuth) {
+        this.hookOnRtspAuth = hookOnRtspAuth;
+    }
+
+    public String getHookOnRtspRealm() {
+        return hookOnRtspRealm;
+    }
+
+    public void setHookOnRtspRealm(String hookOnRtspRealm) {
+        this.hookOnRtspRealm = hookOnRtspRealm;
+    }
+
+    public String getHookOnShellLogin() {
+        return hookOnShellLogin;
+    }
+
+    public void setHookOnShellLogin(String hookOnShellLogin) {
+        this.hookOnShellLogin = hookOnShellLogin;
+    }
+
+    public String getHookOnStreamChanged() {
+        return hookOnStreamChanged;
+    }
+
+    public void setHookOnStreamChanged(String hookOnStreamChanged) {
+        this.hookOnStreamChanged = hookOnStreamChanged;
+    }
+
+    public String getHookOnStreamNoneReader() {
+        return hookOnStreamNoneReader;
+    }
+
+    public void setHookOnStreamNoneReader(String hookOnStreamNoneReader) {
+        this.hookOnStreamNoneReader = hookOnStreamNoneReader;
+    }
+
+    public String getHookOnStreamNotFound() {
+        return hookOnStreamNotFound;
+    }
+
+    public void setHookOnStreamNotFound(String hookOnStreamNotFound) {
+        this.hookOnStreamNotFound = hookOnStreamNotFound;
+    }
+
+    public String getHookTimeoutSec() {
+        return hookTimeoutSec;
+    }
+
+    public void setHookTimeoutSec(String hookTimeoutSec) {
+        this.hookTimeoutSec = hookTimeoutSec;
+    }
+
+    public String getHttpCharSet() {
+        return httpCharSet;
+    }
+
+    public void setHttpCharSet(String httpCharSet) {
+        this.httpCharSet = httpCharSet;
+    }
+
+    public String getHttpKeepAliveSecond() {
+        return httpKeepAliveSecond;
+    }
+
+    public void setHttpKeepAliveSecond(String httpKeepAliveSecond) {
+        this.httpKeepAliveSecond = httpKeepAliveSecond;
+    }
+
+    public String getHttpMaxReqCount() {
+        return httpMaxReqCount;
+    }
+
+    public void setHttpMaxReqCount(String httpMaxReqCount) {
+        this.httpMaxReqCount = httpMaxReqCount;
+    }
+
+    public String getHttpMaxReqSize() {
+        return httpMaxReqSize;
+    }
+
+    public void setHttpMaxReqSize(String httpMaxReqSize) {
+        this.httpMaxReqSize = httpMaxReqSize;
+    }
+
+    public String getHttpNotFound() {
+        return httpNotFound;
+    }
+
+    public void setHttpNotFound(String httpNotFound) {
+        this.httpNotFound = httpNotFound;
+    }
+
+    public String getHttpPort() {
+        return httpPort;
+    }
+
+    public void setHttpPort(String httpPort) {
+        this.httpPort = httpPort;
+    }
+
+    public String getHttpRootPath() {
+        return httpRootPath;
+    }
+
+    public void setHttpRootPath(String httpRootPath) {
+        this.httpRootPath = httpRootPath;
+    }
+
+    public String getHttpSendBufSize() {
+        return httpSendBufSize;
+    }
+
+    public void setHttpSendBufSize(String httpSendBufSize) {
+        this.httpSendBufSize = httpSendBufSize;
+    }
+
+    public String getHttpSSLport() {
+        return httpSSLport;
+    }
+
+    public void setHttpSSLport(String httpSSLport) {
+        this.httpSSLport = httpSSLport;
+    }
+
+    public String getMulticastAddrMax() {
+        return multicastAddrMax;
+    }
+
+    public void setMulticastAddrMax(String multicastAddrMax) {
+        this.multicastAddrMax = multicastAddrMax;
+    }
+
+    public String getMulticastAddrMin() {
+        return multicastAddrMin;
+    }
+
+    public void setMulticastAddrMin(String multicastAddrMin) {
+        this.multicastAddrMin = multicastAddrMin;
+    }
+
+    public String getMulticastUdpTTL() {
+        return multicastUdpTTL;
+    }
+
+    public void setMulticastUdpTTL(String multicastUdpTTL) {
+        this.multicastUdpTTL = multicastUdpTTL;
+    }
+
+    public String getRecordAppName() {
+        return recordAppName;
+    }
+
+    public void setRecordAppName(String recordAppName) {
+        this.recordAppName = recordAppName;
+    }
+
+    public String getRecordFilePath() {
+        return recordFilePath;
+    }
+
+    public void setRecordFilePath(String recordFilePath) {
+        this.recordFilePath = recordFilePath;
+    }
+
+    public String getRecordFileSecond() {
+        return recordFileSecond;
+    }
+
+    public void setRecordFileSecond(String recordFileSecond) {
+        this.recordFileSecond = recordFileSecond;
+    }
+
+    public String getRecordFileSampleMS() {
+        return recordFileSampleMS;
+    }
+
+    public void setRecordFileSampleMS(String recordFileSampleMS) {
+        this.recordFileSampleMS = recordFileSampleMS;
+    }
+
+    public String getRtmpHandshakeSecond() {
+        return rtmpHandshakeSecond;
+    }
+
+    public void setRtmpHandshakeSecond(String rtmpHandshakeSecond) {
+        this.rtmpHandshakeSecond = rtmpHandshakeSecond;
+    }
+
+    public String getRtmpKeepAliveSecond() {
+        return rtmpKeepAliveSecond;
+    }
+
+    public void setRtmpKeepAliveSecond(String rtmpKeepAliveSecond) {
+        this.rtmpKeepAliveSecond = rtmpKeepAliveSecond;
+    }
+
+    public String getRtmpModifyStamp() {
+        return rtmpModifyStamp;
+    }
+
+    public void setRtmpModifyStamp(String rtmpModifyStamp) {
+        this.rtmpModifyStamp = rtmpModifyStamp;
+    }
+
+    public String getRtmpPort() {
+        return rtmpPort;
+    }
+
+    public void setRtmpPort(String rtmpPort) {
+        this.rtmpPort = rtmpPort;
+    }
+
+    public String getRtpAudioMtuSize() {
+        return rtpAudioMtuSize;
+    }
+
+    public void setRtpAudioMtuSize(String rtpAudioMtuSize) {
+        this.rtpAudioMtuSize = rtpAudioMtuSize;
+    }
+
+    public String getRtpClearCount() {
+        return rtpClearCount;
+    }
+
+    public void setRtpClearCount(String rtpClearCount) {
+        this.rtpClearCount = rtpClearCount;
+    }
+
+    public String getRtpCycleMS() {
+        return rtpCycleMS;
+    }
+
+    public void setRtpCycleMS(String rtpCycleMS) {
+        this.rtpCycleMS = rtpCycleMS;
+    }
+
+    public String getRtpMaxRtpCount() {
+        return rtpMaxRtpCount;
+    }
+
+    public void setRtpMaxRtpCount(String rtpMaxRtpCount) {
+        this.rtpMaxRtpCount = rtpMaxRtpCount;
+    }
+
+    public String getRtpVideoMtuSize() {
+        return rtpVideoMtuSize;
+    }
+
+    public void setRtpVideoMtuSize(String rtpVideoMtuSize) {
+        this.rtpVideoMtuSize = rtpVideoMtuSize;
+    }
+
+    public String getRtspAuthBasic() {
+        return rtspAuthBasic;
+    }
+
+    public void setRtspAuthBasic(String rtspAuthBasic) {
+        this.rtspAuthBasic = rtspAuthBasic;
+    }
+
+    public String getRtspHandshakeSecond() {
+        return rtspHandshakeSecond;
+    }
+
+    public void setRtspHandshakeSecond(String rtspHandshakeSecond) {
+        this.rtspHandshakeSecond = rtspHandshakeSecond;
+    }
+
+    public String getRtspKeepAliveSecond() {
+        return rtspKeepAliveSecond;
+    }
+
+    public void setRtspKeepAliveSecond(String rtspKeepAliveSecond) {
+        this.rtspKeepAliveSecond = rtspKeepAliveSecond;
+    }
+
+    public String getRtspPort() {
+        return rtspPort;
+    }
+
+    public void setRtspPort(String rtspPort) {
+        this.rtspPort = rtspPort;
+    }
+
+    public String getRtspSSlport() {
+        return rtspSSlport;
+    }
+
+    public void setRtspSSlport(String rtspSSlport) {
+        this.rtspSSlport = rtspSSlport;
+    }
+
+    public String getShellMaxReqSize() {
+        return shellMaxReqSize;
+    }
+
+    public void setShellMaxReqSize(String shellMaxReqSize) {
+        this.shellMaxReqSize = shellMaxReqSize;
+    }
+
+    public String getShellPhell() {
+        return shellPhell;
+    }
+
+    public void setShellPhell(String shellPhell) {
+        this.shellPhell = shellPhell;
+    }
+}

+ 18 - 8
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java

@@ -49,7 +49,9 @@ public class Device {
 	/**
 	 * 通道列表
 	 */
-	private Map<String,DeviceChannel> channelMap;
+//	private Map<String,DeviceChannel> channelMap;
+
+	private int channelCount;
 
 
 	public String getDeviceId() {
@@ -84,13 +86,13 @@ public class Device {
 		this.host = host;
 	}
 
-	public Map<String, DeviceChannel> getChannelMap() {
-		return channelMap;
-	}
-
-	public void setChannelMap(Map<String, DeviceChannel> channelMap) {
-		this.channelMap = channelMap;
-	}
+//	public Map<String, DeviceChannel> getChannelMap() {
+//		return channelMap;
+//	}
+//
+//	public void setChannelMap(Map<String, DeviceChannel> channelMap) {
+//		this.channelMap = channelMap;
+//	}
 
 	public String getManufacturer() {
 		return manufacturer;
@@ -123,4 +125,12 @@ public class Device {
 	public void setOnline(int online) {
 		this.online = online;
 	}
+
+	public int getChannelCount() {
+		return channelCount;
+	}
+
+	public void setChannelCount(int channelCount) {
+		this.channelCount = channelCount;
+	}
 }

+ 27 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java

@@ -100,7 +100,12 @@ public class DeviceChannel {
 	/**
 	 * 密码
 	 */
-	private String password;	 
+	private String password;
+
+	/**
+	 * 云台控制
+	 */
+	private int PTZType;
 	
 	/**
 	 * 在线/离线
@@ -123,6 +128,11 @@ public class DeviceChannel {
 	 */
 	private double latitude;
 
+	/**
+	 * 流唯一编号,存在表示正在直播
+	 */
+	private String  ssrc;
+
 	public String getChannelId() {
 		return channelId;
 	}
@@ -306,4 +316,20 @@ public class DeviceChannel {
 	public void setLatitude(double latitude) {
 		this.latitude = latitude;
 	}
+
+	public int getPTZType() {
+		return PTZType;
+	}
+
+	public void setPTZType(int PTZType) {
+		this.PTZType = PTZType;
+	}
+
+	public String getSsrc() {
+		return ssrc;
+	}
+
+	public void setSsrc(String ssrc) {
+		this.ssrc = ssrc;
+	}
 }

+ 2 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.transmit.cmd;
 
+import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 
 /**    
@@ -69,7 +70,7 @@ public interface ISIPCommander {
 	 * @param device  视频设备
 	 * @param channelId  预览通道
 	 */
-	public String playStreamCmd(Device device,String channelId);
+	public StreamInfo playStreamCmd(Device device, String channelId);
 	
 	/**
 	 * 请求回放视频流

+ 31 - 5
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@@ -15,8 +15,14 @@ import javax.sip.address.SipURI;
 import javax.sip.header.ViaHeader;
 import javax.sip.message.Request;
 
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import com.genersoft.iot.vmp.conf.SipConfig;
@@ -42,6 +48,9 @@ public class SIPCommander implements ISIPCommander {
 	
 	@Autowired
 	private VideoStreamSessionManager streamSession;
+
+	@Autowired
+	private IVideoManagerStorager storager;
 	
 	@Autowired
 	@Qualifier(value="tcpSipProvider")
@@ -50,6 +59,9 @@ public class SIPCommander implements ISIPCommander {
 	@Autowired
 	@Qualifier(value="udpSipProvider")
 	private SipProvider udpSipProvider;
+
+	@Value("${media.ip}")
+	private String mediaIp;
 	
 	/**
 	 * 云台方向放控制,使用配置文件中的默认镜头移动速度
@@ -58,7 +70,6 @@ public class SIPCommander implements ISIPCommander {
 	 * @param channelId  预览通道
 	 * @param leftRight  镜头左移右移 0:停止 1:左移 2:右移
      * @param upDown     镜头上移下移 0:停止 1:上移 2:下移
-     * @param moveSpeed  镜头移动速度
 	 */
 	@Override
 	public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) {
@@ -191,7 +202,7 @@ public class SIPCommander implements ISIPCommander {
 	 * @param channelId  预览通道
 	 */  
 	@Override
-	public String playStreamCmd(Device device, String channelId) {
+	public StreamInfo playStreamCmd(Device device, String channelId) {
 		try {
 			
 			String ssrc = streamSession.createPlaySsrc();
@@ -223,7 +234,24 @@ public class SIPCommander implements ISIPCommander {
 	
 	        ClientTransaction transaction = transmitRequest(device, request);
 	        streamSession.put(ssrc, transaction);
-			return ssrc;
+			DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
+			if (deviceChannel != null) {
+				deviceChannel.setSsrc(ssrc);
+				storager.updateChannel(device.getDeviceId(), deviceChannel);
+			}
+			MediaServerConfig mediaInfo = storager.getMediaInfo();
+			StreamInfo streamInfo = new StreamInfo();
+			streamInfo.setSsrc(ssrc);
+//			String streamId = Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()));
+			String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); // ZLM 要求大写且首位补零
+			streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaIp, mediaInfo.getHttpPort(), streamId));
+			streamInfo.setWS_FLV(String.format("ws://%s:%s/rtp/%s.flv", mediaIp, mediaInfo.getHttpPort(), streamId));
+			streamInfo.setRTMP(String.format("rtmp://%s:%s/rtp/%s", mediaIp, mediaInfo.getRtmpPort(), streamId));
+			streamInfo.setHLS(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaIp, mediaInfo.getHttpPort(), streamId));
+			streamInfo.setRTSP(String.format("rtsp://%s:%s/rtp/%s", mediaIp, mediaInfo.getRtspPort(), streamId));
+
+			storager.startPlay(device.getDeviceId(), channelId, streamInfo);
+			return streamInfo;
 		} catch ( SipException | ParseException | InvalidArgumentException e) {
 			e.printStackTrace();
 			return null;
@@ -281,8 +309,6 @@ public class SIPCommander implements ISIPCommander {
 	/**
 	 * 视频流停止
 	 * 
-	 * @param device  视频设备
-	 * @param channelId  预览通道
 	 */
 	@Override
 	public void streamByeCmd(String ssrc) {

+ 9 - 12
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java

@@ -76,8 +76,6 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 	 * 处理MESSAGE请求
 	 *  
 	 * @param evt
-	 * @param layer
-	 * @param transaction  
 	 */  
 	@Override
 	public void process(RequestEvent evt) {
@@ -127,7 +125,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 			device.setManufacturer(XmlUtil.getText(rootElement,"Manufacturer"));
 			device.setModel(XmlUtil.getText(rootElement,"Model"));
 			device.setFirmware(XmlUtil.getText(rootElement,"Firmware"));
-			storager.update(device);
+			storager.updateDevice(device);
 			
 			RequestMessage msg = new RequestMessage();
 			msg.setDeviceId(deviceId);
@@ -158,11 +156,6 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 				if (device == null) {
 					return;
 				}
-				Map<String, DeviceChannel> channelMap = device.getChannelMap();
-				if (channelMap == null) {
-					channelMap = new HashMap<String, DeviceChannel>(5);
-					device.setChannelMap(channelMap);
-				}
 				// 遍历DeviceList
 				while (deviceListIterator.hasNext()) {
 					Element itemDevice = deviceListIterator.next();
@@ -175,7 +168,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 					String channelName = channdelNameElement != null ? channdelNameElement.getText().toString() : "";
 					Element statusElement = itemDevice.element("Status");
 					String status = statusElement != null ? statusElement.getText().toString() : "ON";
-					DeviceChannel deviceChannel = channelMap.containsKey(channelDeviceId) ? channelMap.get(channelDeviceId) : new DeviceChannel();
+					DeviceChannel deviceChannel = new DeviceChannel();
 					deviceChannel.setName(channelName);
 					deviceChannel.setChannelId(channelDeviceId);
 					if(status.equals("ON")) {
@@ -205,10 +198,12 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 					deviceChannel.setPassword(XmlUtil.getText(itemDevice,"Password"));
 					deviceChannel.setLongitude(itemDevice.element("Longitude") == null? 0.00:Double.parseDouble(XmlUtil.getText(itemDevice,"Longitude")));
 					deviceChannel.setLatitude(itemDevice.element("Latitude") == null? 0.00:Double.parseDouble(XmlUtil.getText(itemDevice,"Latitude")));
-					channelMap.put(channelDeviceId, deviceChannel);
+					deviceChannel.setPTZType(itemDevice.element("PTZType") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"PTZType")));
+					storager.updateChannel(device.getDeviceId(), deviceChannel);
 				}
 				// 更新
-				storager.update(device);
+				storager.updateDevice(device);
+
 				RequestMessage msg = new RequestMessage();
 				msg.setDeviceId(deviceId);
 				msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG);
@@ -232,13 +227,15 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 			
 			Device device = storager.queryVideoDevice(deviceId);
 			if (device == null) {
+				// TODO 也可能是通道
+//				storager.queryChannel(deviceId)
 				return;
 			}
 			device.setName(XmlUtil.getText(rootElement,"DeviceName"));
 			device.setManufacturer(XmlUtil.getText(rootElement,"Manufacturer"));
 			device.setModel(XmlUtil.getText(rootElement,"Model"));
 			device.setFirmware(XmlUtil.getText(rootElement,"Firmware"));
-			storager.update(device);
+			storager.updateDevice(device);
 			cmder.catalogQuery(device);
 		} catch (DocumentException e) {
 			e.printStackTrace();

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java

@@ -138,7 +138,7 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
 			// 下发catelog查询目录
 			if (registerFlag == 1 && device != null) {
 				System.out.println("注册成功! deviceId:" + device.getDeviceId());
-				storager.update(device);
+				storager.updateDevice(device);
 				publisher.onlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_ONLINE_REGISTER);
 				handler.onRegister(device);
 			} else if (registerFlag == 2) {

+ 43 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/SolrProxyServletConfiguration.java

@@ -0,0 +1,43 @@
+package com.genersoft.iot.vmp.media.zlm;
+
+import com.google.common.collect.ImmutableMap;
+import org.mitre.dsmiley.httpproxy.ProxyServlet;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.servlet.Servlet;
+import java.util.Map;
+
+/**
+ * 对查询流媒体信息的请求进行反向代理
+ */
+@Configuration
+public class SolrProxyServletConfiguration {
+
+    // 读取配置文件中路由设置
+    @Value("${proxy.servlet_url}")
+    private String servlet_url;
+    // 读取配置中代理目标地址
+    @Value("${proxy.target_url}")
+    private String target_url;
+
+
+
+    @Bean
+    public Servlet createProxyServlet(){
+        // 创建新的ProxyServlet
+        return new ProxyServlet();
+    }
+    @Bean
+    public ServletRegistrationBean proxyServletRegistration(){
+        ServletRegistrationBean registrationBean = new ServletRegistrationBean(createProxyServlet(), servlet_url);
+        //设置网址以及参数
+        Map<String, String> params = ImmutableMap.of(
+                "targetUri", target_url,
+                "log", "true");
+        registrationBean.setInitParameters(params);
+        return registrationBean;
+    }
+}

+ 15 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java

@@ -1,7 +1,13 @@
 package com.genersoft.iot.vmp.media.zlm;
 
 import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -29,6 +35,9 @@ public class ZLMHttpHookListener {
 	
 	@Autowired
 	private SIPCommander cmder;
+
+	@Autowired
+	private IVideoManagerStorager storager;
 	
 	/**
 	 * 流量统计事件,播放器或推流器断开时并且耗用流量超过特定阈值时会触发此事件,阈值通过配置文件general.flowThreshold配置;此事件对回复不敏感。
@@ -263,6 +272,12 @@ public class ZLMHttpHookListener {
 		if (logger.isDebugEnabled()) {
 			logger.debug("ZLM HOOK on_server_started API调用,参数:" + json.toString());
 		}
+
+//		String data = json.getString("data");
+//		List<MediaServerConfig> mediaServerConfigs = JSON.parseArray(JSON.toJSONString(json), MediaServerConfig.class);
+//		MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0);
+		MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class);
+		storager.updateMediaInfo(mediaServerConfig);
 		// TODO Auto-generated method stub
 		
 		JSONObject ret = new JSONObject();

+ 93 - 4
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java

@@ -2,7 +2,12 @@ package com.genersoft.iot.vmp.storager;
 
 import java.util.List;
 
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.common.PageResult;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.conf.MediaServerConfig;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 
 /**    
  * @Description:视频设备数据存储接口
@@ -10,7 +15,20 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
  * @date:   2020年5月6日 下午2:14:31     
  */
 public interface IVideoManagerStorager {
-	
+
+	/**
+	 * 更新流媒体信息
+	 * @param mediaServerConfig
+	 * @return
+	 */
+	public boolean updateMediaInfo(MediaServerConfig mediaServerConfig);
+
+	/**
+	 * 获取流媒体信息
+	 * @return
+	 */
+	public MediaServerConfig getMediaInfo();
+
 	/**   
 	 * 根据设备ID判断设备是否存在
 	 * 
@@ -33,7 +51,15 @@ public interface IVideoManagerStorager {
 	 * @param device 设备对象
 	 * @return true:创建成功  false:创建失败
 	 */
-	public boolean update(Device device);
+	public boolean updateDevice(Device device);
+
+	/**
+	 * 添加设备通道
+	 *
+	 * @param deviceId 设备id
+	 * @param channel 通道
+	 */
+	public void updateChannel(String deviceId, DeviceChannel channel);
 	
 	/**   
 	 * 获取设备
@@ -42,15 +68,47 @@ public interface IVideoManagerStorager {
 	 * @return DShadow 设备对象
 	 */
 	public Device queryVideoDevice(String deviceId);
-	
+
+	/**
+	 * 获取某个设备的通道列表
+	 *
+	 * @param deviceId 设备ID
+	 * @param page 分页 当前页
+	 * @param count 每页数量
+	 * @return
+	 */
+	public PageResult queryChannelsByDeviceId(String deviceId, int page, int count);
+
+	/**
+	 * 获取某个设备的通道列表
+	 *
+	 * @param deviceId 设备ID
+	 * @return
+	 */
+	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId);
+	/**
+	 * 获取某个设备的通道
+	 * @param deviceId 设备ID
+	 * @param channelId 通道ID
+	 */
+	public DeviceChannel queryChannel(String deviceId, String channelId);
+
 	/**   
 	 * 获取多个设备
 	 * 
 	 * @param deviceIds 设备ID数组
 	 * @return List<Device> 设备对象数组
 	 */
+	public PageResult<Device> queryVideoDeviceList(String[] deviceIds, int page, int count);
+
+	/**
+	 * 获取多个设备
+	 *
+	 * @param deviceIds 设备ID数组
+	 * @return List<Device> 设备对象数组
+	 */
 	public List<Device> queryVideoDeviceList(String[] deviceIds);
-	
+
 	/**   
 	 * 删除设备
 	 * 
@@ -74,4 +132,35 @@ public interface IVideoManagerStorager {
 	 * @return true:更新成功  false:更新失败
 	 */
 	public boolean outline(String deviceId);
+
+	/**
+	 * 开始播放时将流存入
+	 *
+	 * @param deviceId 设备ID
+	 * @param channelId 通道ID
+	 * @param stream 流信息
+	 * @return
+	 */
+	public boolean startPlay(String deviceId, String channelId, StreamInfo stream);
+
+	/**
+	 * 停止播放时删除
+	 *
+	 * @param deviceId 设备ID
+	 * @param channelId 通道ID
+	 * @return
+	 */
+	public boolean stopPlay(String deviceId, String channelId);
+
+	/**
+	 * 查找视频流
+	 *
+	 * @param deviceId 设备ID
+	 * @param channelId 通道ID
+	 * @return
+	 */
+	public StreamInfo queryPlay(String deviceId, String channelId);
+
+
+
 }

+ 58 - 10
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java

@@ -2,6 +2,10 @@ package com.genersoft.iot.vmp.storager.jdbc;
 
 import java.util.List;
 
+import com.genersoft.iot.vmp.common.PageResult;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Service;
 
@@ -17,7 +21,17 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 @Component("jdbcStorager")
 public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
 
-	/**   
+	@Override
+	public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) {
+		return false;
+	}
+
+	@Override
+	public MediaServerConfig getMediaInfo() {
+		return null;
+	}
+
+	/**
 	 * 根据设备ID判断设备是否存在
 	 * 
 	 * @param deviceId 设备ID
@@ -40,19 +54,18 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
 		// TODO Auto-generated method stub
 		return false;
 	}
-	
-	/**   
-	 * 视频设备更新
-	 * 
-	 * @param device 设备对象
-	 * @return true:更新成功  false:更新失败
-	 */  
+
 	@Override
-	public boolean update(Device device) {
-		// TODO Auto-generated method stub
+	public boolean updateDevice(Device device) {
 		return false;
 	}
 
+	@Override
+	public void updateChannel(String deviceId, DeviceChannel channel) {
+
+	}
+
+
 	/**   
 	 * 获取设备
 	 * 
@@ -65,6 +78,26 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
 		return null;
 	}
 
+	@Override
+	public PageResult queryChannelsByDeviceId(String deviceId, int page, int count) {
+		return null;
+	}
+
+	@Override
+	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
+		return null;
+	}
+
+	@Override
+	public DeviceChannel queryChannel(String deviceId, String channelId) {
+		return null;
+	}
+
+	@Override
+	public PageResult<Device> queryVideoDeviceList(String[] deviceIds, int page, int count) {
+		return null;
+	}
+
 	/**   
 	 * 获取多个设备
 	 * 
@@ -113,4 +146,19 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
 		return false;
 	}
 
+	@Override
+	public boolean startPlay(String deviceId, String channelId, StreamInfo stream) {
+		return false;
+	}
+
+	@Override
+	public boolean stopPlay(String deviceId, String channelId) {
+		return false;
+	}
+
+	@Override
+	public StreamInfo queryPlay(String deviceId, String channelId) {
+		return null;
+	}
+
 }

+ 166 - 16
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java

@@ -3,6 +3,12 @@ package com.genersoft.iot.vmp.storager.redis;
 import java.util.ArrayList;
 import java.util.List;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.common.PageResult;
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -21,7 +27,8 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 
 	@Autowired
     private RedisUtil redis;
-	
+
+
 	/**   
 	 * 根据设备ID判断设备是否存在
 	 * 
@@ -30,7 +37,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	 */ 
 	@Override
 	public boolean exists(String deviceId) {
-		return redis.hasKey(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
+		return redis.hasKey(VideoManagerConstants.DEVICE_PREFIX+deviceId);
 	}
 
 	/**   
@@ -41,9 +48,11 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	 */ 
 	@Override
 	public boolean create(Device device) {
-		return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
+		return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
 	}
-	
+
+
+
 	/**   
 	 * 视频设备更新
 	 * 
@@ -51,8 +60,26 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	 * @return true:更新成功  false:更新失败
 	 */  
 	@Override
-	public boolean update(Device device) {
-		return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
+	public boolean updateDevice(Device device) {
+		List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + device.getDeviceId() + "_" + "*");
+		// 更新device中的通道数量
+		device.setChannelCount(deviceChannelList.size());
+		// 存储device
+		return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
+
+
+	}
+
+	@Override
+	public void updateChannel(String deviceId, DeviceChannel channel) {
+		// 存储通道
+		redis.set(VideoManagerConstants.CACHEKEY_PREFIX+deviceId + "_" + channel.getChannelId(),
+				channel);
+		List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
+		// 更新device中的通道数量
+		Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
+		device.setChannelCount(deviceChannelList.size());
+		redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
 	}
 
 	/**   
@@ -63,26 +90,94 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	 */  
 	@Override
 	public Device queryVideoDevice(String deviceId) {
-		return (Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
+		return (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
 	}
 
-	/**   
+	@Override
+	public PageResult queryChannelsByDeviceId(String deviceId, int page, int count) {
+		List<DeviceChannel> result = new ArrayList<>();
+		PageResult pageResult = new PageResult<DeviceChannel>();
+		List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
+		pageResult.setPage(page);
+		pageResult.setCount(count);
+		pageResult.setTotal(deviceChannelList.size());
+		int maxCount = (page + 1 ) * count;
+		if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
+			for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) {
+				result.add((DeviceChannel)redis.get((String)deviceChannelList.get(i)));
+			}
+			pageResult.setData(result);
+		}
+
+		return pageResult;
+	}
+
+	@Override
+	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
+		List<DeviceChannel> result = new ArrayList<>();
+		List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
+		if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
+			for (int i = 0; i < deviceChannelList.size(); i++) {
+				result.add((DeviceChannel)redis.get((String)deviceChannelList.get(i)));
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public DeviceChannel queryChannel(String deviceId, String channelId) {
+		return (DeviceChannel)redis.get(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + channelId);
+	}
+
+
+	/**
 	 * 获取多个设备
 	 * 
 	 * @param deviceIds 设备ID数组
 	 * @return List<Device> 设备对象数组
 	 */  
 	@Override
+	public PageResult<Device> queryVideoDeviceList(String[] deviceIds, int page, int count) {
+		List<Device> devices = new ArrayList<>();
+		PageResult pageResult = new PageResult<Device>();
+		pageResult.setPage(page);
+		pageResult.setCount(count);
+
+		if (deviceIds == null || deviceIds.length == 0) {
+
+			List<Object> deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*");
+			pageResult.setTotal(deviceIdList.size());
+			int maxCount = (page + 1)* count;
+			for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) {
+				devices.add((Device)redis.get((String)deviceIdList.get(i)));
+			}
+		} else {
+			for (int i = 0; i < deviceIds.length; i++) {
+				devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]));
+			}
+		}
+		pageResult.setData(devices);
+		return pageResult;
+	}
+
+	/**
+	 * 获取多个设备
+	 *
+	 * @param deviceIds 设备ID数组
+	 * @return List<Device> 设备对象数组
+	 */
+	@Override
 	public List<Device> queryVideoDeviceList(String[] deviceIds) {
 		List<Device> devices = new ArrayList<>();
+
 		if (deviceIds == null || deviceIds.length == 0) {
-			List<Object> deviceIdList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX+"*");
+			List<Object> deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*");
 			for (int i = 0; i < deviceIdList.size(); i++) {
 				devices.add((Device)redis.get((String)deviceIdList.get(i)));
 			}
 		} else {
 			for (int i = 0; i < deviceIds.length; i++) {
-				devices.add((Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceIds[i]));
+				devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]));
 			}
 		}
 		return devices;
@@ -96,7 +191,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	 */  
 	@Override
 	public boolean delete(String deviceId) {
-		return redis.del(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
+		return redis.del(VideoManagerConstants.DEVICE_PREFIX+deviceId);
 	}
 
 	/**   
@@ -107,9 +202,9 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	 */ 
 	@Override
 	public boolean online(String deviceId) {
-		Device device = (Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
+		Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
 		device.setOnline(1);
-		return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
+		return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
 	}
 
 	/**   
@@ -120,9 +215,64 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	 */ 
 	@Override
 	public boolean outline(String deviceId) {
-		Device device = (Device)redis.get(VideoManagerConstants.CACHEKEY_PREFIX+deviceId);
+		Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
+		if (device == null) return false;
 		device.setOnline(0);
-		return redis.set(VideoManagerConstants.CACHEKEY_PREFIX+device.getDeviceId(), device);
+		return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
+	}
+
+	/**
+	 * 开始播放时将流存入redis
+	 *
+	 * @param deviceId 设备ID
+	 * @param channelId 通道ID
+	 * @return
+	 */
+	@Override
+	public boolean startPlay(String deviceId, String channelId, StreamInfo stream) {
+		return redis.set(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId),
+				stream);
+	}
+
+	/**
+	 * 停止播放时从redis删除
+	 *
+	 * @param deviceId 设备ID
+	 * @param channelId 通道ID
+	 * @return
+	 */
+	@Override
+	public boolean stopPlay(String deviceId, String channelId) {
+		return redis.del(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId));
+	}
+
+	/**
+	 * 查询播放列表
+	 * @param deviceId 设备ID
+	 * @param channelId 通道ID
+	 * @return
+	 */
+	@Override
+	public StreamInfo queryPlay(String deviceId, String channelId) {
+		return (StreamInfo)redis.get(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId));
+	}
+
+	/**
+	 * 更新流媒体信息
+	 * @param mediaServerConfig
+	 * @return
+	 */
+	@Override
+	public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) {
+		return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig);
+	}
+
+	/**
+	 * 获取流媒体信息
+	 * @return
+	 */
+	@Override
+	public MediaServerConfig getMediaInfo() {
+		return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
 	}
-	
 }

+ 116 - 0
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java

@@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ZSetOperations;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
@@ -389,6 +390,121 @@ public class RedisUtil {
             return 0;
         }
     }
+//    ============================== ZSet ==============================
+
+    /**
+     * 添加一个元素, zset与set最大的区别就是每个元素都有一个score,因此有个排序的辅助功能;  zadd
+     *
+     * @param key
+     * @param value
+     * @param score
+     */
+    public void zAdd(String key, String value, double score) {
+        redisTemplate.opsForZSet().add(key, value, score);
+    }
+
+    /**
+     * 删除元素 zrem
+     *
+     * @param key
+     * @param value
+     */
+    public void zRemove(String key, String value) {
+        redisTemplate.opsForZSet().remove(key, value);
+    }
+
+    /**
+     * score的增加or减少 zincrby
+     *
+     * @param key
+     * @param value
+     * @param score
+     */
+    public Double zIncrScore(String key, String value, double score) {
+        return redisTemplate.opsForZSet().incrementScore(key, value, score);
+    }
+
+    /**
+     * 查询value对应的score   zscore
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public Double zScore(String key, String value) {
+        return redisTemplate.opsForZSet().score(key, value);
+    }
+
+    /**
+     * 判断value在zset中的排名  zrank
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public Long zRank(String key, String value) {
+        return redisTemplate.opsForZSet().rank(key, value);
+    }
+
+    /**
+     * 返回集合的长度
+     *
+     * @param key
+     * @return
+     */
+    public Long zSize(String key) {
+        return redisTemplate.opsForZSet().zCard(key);
+    }
+
+    /**
+     * 查询集合中指定顺序的值, 0 -1 表示获取全部的集合内容  zrange
+     *
+     * 返回有序的集合,score小的在前面
+     *
+     * @param key
+     * @param start
+     * @param end
+     * @return
+     */
+    public Set<String> ZRange(String key, int start, int end) {
+        return redisTemplate.opsForZSet().range(key, start, end);
+    }
+    /**
+     * 查询集合中指定顺序的值和score,0, -1 表示获取全部的集合内容
+     *
+     * @param key
+     * @param start
+     * @param end
+     * @return
+     */
+    public Set<ZSetOperations.TypedTuple<String>> zRangeWithScore(String key, int start, int end) {
+        return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
+    }
+    /**
+     * 查询集合中指定顺序的值  zrevrange
+     *
+     * 返回有序的集合中,score大的在前面
+     *
+     * @param key
+     * @param start
+     * @param end
+     * @return
+     */
+    public Set<String> zRevRange(String key, int start, int end) {
+        return redisTemplate.opsForZSet().reverseRange(key, start, end);
+    }
+    /**
+     * 根据score的值,来获取满足条件的集合  zrangebyscore
+     *
+     * @param key
+     * @param min
+     * @param max
+     * @return
+     */
+    public Set<String> zSortRange(String key, int min, int max) {
+        return redisTemplate.opsForZSet().rangeByScore(key, min, max);
+    }
+
 
 //    ============================== List ==============================
 

+ 21 - 3
src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java

@@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.vmanager.device;
 
 import java.util.List;
 
+import com.genersoft.iot.vmp.common.PageResult;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -53,14 +55,30 @@ public class DeviceController {
 	}
 	
 	@GetMapping("/devices")
-	public ResponseEntity<List<Device>> devices(){
+	public PageResult<Device> devices(int page, int count){
 		
 		if (logger.isDebugEnabled()) {
 			logger.debug("查询所有视频设备API调用");
 		}
 		
-		List<Device> deviceList = storager.queryVideoDeviceList(null);
-		return new ResponseEntity<>(deviceList,HttpStatus.OK);
+		return storager.queryVideoDeviceList(null, page, count);
+	}
+
+	/**
+	 * 分页查询通道数
+	 * @param deviceId 设备id
+	 * @param page 当前页
+	 * @param count 每页条数
+	 * @return 通道列表
+	 */
+	@GetMapping("devices/{deviceId}/channels")
+	public ResponseEntity<PageResult> channels(@PathVariable String deviceId, int page, int count){
+
+		if (logger.isDebugEnabled()) {
+			logger.debug("查询所有视频设备API调用");
+		}
+		PageResult pageResult = storager.queryChannelsByDeviceId(deviceId, page, count);
+		return new ResponseEntity<>(pageResult,HttpStatus.OK);
 	}
 	
 	@PostMapping("/devices/{deviceId}/sync")

+ 5 - 4
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.vmanager.play;
 
+import com.genersoft.iot.vmp.common.StreamInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -34,16 +35,16 @@ public class PlayController {
 	public ResponseEntity<String> play(@PathVariable String deviceId,@PathVariable String channelId){
 		
 		Device device = storager.queryVideoDevice(deviceId);
-		String ssrc = cmder.playStreamCmd(device, channelId);
+		StreamInfo streamInfo = cmder.playStreamCmd(device, channelId);
 		
 		if (logger.isDebugEnabled()) {
 			logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId));
-			logger.debug("设备预览 API调用,ssrc:"+ssrc+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(ssrc)));
+			logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
 		}
 		
-		if(ssrc!=null) {
+		if(streamInfo!=null) {
 			JSONObject json = new JSONObject();
-			json.put("ssrc", ssrc);
+			json.put("ssrc", streamInfo.getSsrc());
 			return new ResponseEntity<String>(json.toString(),HttpStatus.OK);
 		} else {
 			logger.warn("设备预览API调用失败!");

+ 30 - 0
src/main/java/com/genersoft/iot/vmp/web/AuthController.java

@@ -0,0 +1,30 @@
+package com.genersoft.iot.vmp.web;
+
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+@CrossOrigin
+@RestController
+@RequestMapping(value = "/auth")
+public class AuthController {
+
+    @Value("${auth.username}")
+    private String username;
+
+    @Value("${auth.password}")
+    private String password;
+
+    @RequestMapping("/login")
+    public Object devices(String username, String password){
+        if (!StringUtils.isEmpty(username) && username.equals(username)
+                && !StringUtils.isEmpty(password) && password.equals(password)) {
+            return "success";
+        }else {
+            return "fait";
+        }
+    }
+}

+ 21 - 11
src/main/resources/application.yml

@@ -7,27 +7,26 @@ spring:
         communicate: http
     redis: 
         # Redis服务器IP
-        #host: 10.24.20.63
-        host: 127.0.0.1
+        host: 192.168.1.141
         #端口号
         port: 6379
-        datebase: 0
+        database: 6
         #访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
-        password:
+        password: 4767cb971b40a1300fa09b7f87b09d1c
         #超时时间
         timeout: 10000
     datasource: 
         name: eiot
-        url: jdbc:mysql://10.24.20.63:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
+        url: jdbc:mysql://192.168.1.141:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
         username: root
-        password: 123456
+        password: root
         type: com.alibaba.druid.pool.DruidDataSource
         driver-class-name: com.mysql.jdbc.Driver
 server:
-    port: 8080
+    port: 18080
 sip:
 #   ip: 10.200.64.63
-    ip: 192.168.0.102
+    ip: 192.168.1.20
     port: 5060
     # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007)
     # 后两位为行业编码,定义参照附录D.3
@@ -35,8 +34,19 @@ sip:
     domain: 3701020049
     id: 37010200492000000001
     # 默认设备认证密码,后续扩展使用设备单独密码
-    password: admin123
+    password: 12345678
 media:
 #   ip: 10.200.64.88
-    ip: 192.168.0.102
-    port: 10000
+    ip: 192.168.1.20
+    port: 10000
+
+# 自定义代理相关配置
+# 代理的本地路由
+proxy:
+     servlet_url: /media/*
+        # 要代理的地址
+     target_url: http://127.0.0.1:10080
+
+auth: #32位小写md5加密(默认密码为admin)
+    username: admin
+    password: 21232f297a57a5a743894a0e4a801fc3