diff --git a/pom.xml b/pom.xml index 528f7655..31adf4fe 100644 --- a/pom.xml +++ b/pom.xml @@ -144,17 +144,20 @@ 2.9.0 - - org.mitre.dsmiley.httpproxy - smiley-http-proxy-servlet - 1.7 - com.google.guava guava 18.0 - + + + + com.squareup.okhttp3 + okhttp + 4.9.0 + + + diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java index 55d0a636..00bd9951 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java @@ -143,6 +143,11 @@ public class DeviceChannel { */ private String ssrc; + /** + * 是否含有音频 + */ + private boolean hasAudio; + public String getChannelId() { return channelId; } @@ -371,4 +376,16 @@ public class DeviceChannel { public void setSubCount(int subCount) { this.subCount = subCount; } + + public void setPTZTypeText(String PTZTypeText) { + this.PTZTypeText = PTZTypeText; + } + + public boolean isHasAudio() { + return hasAudio; + } + + public void setHasAudio(boolean hasAudio) { + this.hasAudio = hasAudio; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 481bb43b..3cc1376d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -241,13 +241,6 @@ public class SIPCommander implements ISIPCommander { 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", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId)); -// streamInfo.setWS_FLV(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId)); -// streamInfo.setRTMP(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId)); -// streamInfo.setHLS(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId)); -// streamInfo.setRTSP(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId)); streamInfo.setCahnnelId(channelId); streamInfo.setDeviceID(device.getDeviceId()); storager.startPlay(streamInfo); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java index 774cd60d..927168f5 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java @@ -200,6 +200,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { 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"))); deviceChannel.setPTZType(itemDevice.element("PTZType") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"PTZType"))); + deviceChannel.setHasAudio(false); // 默认含有音频为false storager.updateChannel(device.getDeviceId(), deviceChannel); } // 更新 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java index 0275f843..4b2cabd4 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java @@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.media.zlm; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import org.apache.http.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index 22ebe521..666cc258 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.utils.IpUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; @@ -44,7 +45,13 @@ public class ZLMHttpHookListener { @Autowired private IVideoManagerStorager storager; - + + @Value("${media.ip}") + private String mediaIp; + + @Value("${media.port}") + private int mediaPort; + /** * 流量统计事件,播放器或推流器断开时并且耗用流量超过特定阈值时会触发此事件,阈值通过配置文件general.flowThreshold配置;此事件对回复不敏感。 * @@ -308,6 +315,7 @@ public class ZLMHttpHookListener { // List mediaServerConfigs = JSON.parseArray(JSON.toJSONString(json), MediaServerConfig.class); // MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0); MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class); + mediaServerConfig.setLocalIP(mediaIp); storager.updateMediaInfo(mediaServerConfig); // TODO Auto-generated method stub diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java new file mode 100644 index 00000000..8dc8e501 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java @@ -0,0 +1,152 @@ +package com.genersoft.iot.vmp.media.zlm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +@Component +@Order(value=1) +public class ZLMRunner implements CommandLineRunner { + + private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class); + + @Autowired + private IVideoManagerStorager storager; + + @Value("${media.ip}") + private String mediaIp; + + @Value("${media.port}") + private int mediaPort; + + @Value("${media.secret}") + private String mediaSecret; + + @Value("${sip.ip}") + private String sipIP; + + @Value("${server.port}") + private String serverPort; + + @Override + public void run(String... strings) throws Exception { + // 获取zlm信息 + logger.info("等待zlm接入..."); + MediaServerConfig mediaServerConfig = getMediaServerConfig(); + if (mediaServerConfig != null) { + logger.info("zlm接入成功..."); + storager.updateMediaInfo(mediaServerConfig); + logger.info("设置zlm..."); + saveZLMConfig(); + + } + } + + + + public MediaServerConfig getMediaServerConfig() { + MediaServerConfig mediaServerConfig = null; + OkHttpClient client = new OkHttpClient(); + String url = String.format("http://%s:%s/index/api/getServerConfig?secret=%s", mediaIp, mediaPort, mediaSecret); + //创建一个Request + Request request = new Request.Builder() + .get() + .url(url) + .build(); + //通过client发起请求 + final Call call = client.newCall(request); + //执行同步请求,获取Response对象 + Response response = null; + try { + response = call.execute(); + if (response.isSuccessful()) { + String responseStr = response.body().string(); + if (responseStr != null) { + JSONObject responseJSON = JSON.parseObject(responseStr); + JSONArray data = responseJSON.getJSONArray("data"); + if (data != null && data.size() > 0) { + mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class); + mediaServerConfig.setLocalIP(mediaIp); + } + } + }else { + logger.error("getMediaServerConfig失败, 1s后重试"); + Thread.sleep(1000); + getMediaServerConfig(); + } + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + return mediaServerConfig; + } + + private void saveZLMConfig() { + String hookIP = sipIP; + if (mediaIp.equals(sipIP)) { + hookIP = "127.0.0.1"; + } + OkHttpClient client = new OkHttpClient(); + String url = String.format("http://%s:%s/index/api/setServerConfig", mediaIp, mediaPort); + String hookPrex = String.format("http://%s:%s/index/hook", hookIP, serverPort); + + RequestBody body = new FormBody.Builder() + .add("secret",mediaSecret) + .add("hook.enable","1") + .add("hook.on_flow_report","") + .add("hook.on_http_access","") + .add("hook.on_publish",String.format("%s/on_publish", hookPrex)) + .add("hook.on_record_mp4","") + .add("hook.on_record_ts","") + .add("hook.on_rtsp_auth","") + .add("hook.on_rtsp_realm","") + .add("hook.on_server_started",String.format("%s/on_server_started", hookPrex)) + .add("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex)) + .add("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex)) + .add("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex)) + .add("hook.timeoutSec","20") + .build(); + + Request request = new Request.Builder() + .post(body) + .url(url) + .build(); + client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + logger.error("saveZLMConfig ",e); + } + @Override + public void onResponse(Call call, Response response) throws IOException { + if (response.isSuccessful()) { + String responseStr = response.body().string(); + if (responseStr != null) { + JSONObject responseJSON = JSON.parseObject(responseStr); + if (responseJSON.getInteger("code") == 0) { + logger.info("设置zlm成功"); + }else { + logger.info("设置zlm失败: " + responseJSON.getString("msg")); + } + } + } + + } + }); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java index 5ca8b1c4..38a64762 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java @@ -344,6 +344,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { */ @Override public boolean stopPlay(StreamInfo streamInfo) { + if (streamInfo == null) return false; return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, streamInfo.getSsrc(), streamInfo.getDeviceID(), diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java index fa86ee29..1b4689a8 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java @@ -144,4 +144,10 @@ public class DeviceController { PageResult pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count); return new ResponseEntity<>(pageResult,HttpStatus.OK); } + + @PostMapping("channel/update/{deviceId}") + public ResponseEntity updateChannel(@PathVariable String deviceId,DeviceChannel channel){ + storager.updateChannel(deviceId, channel); + return new ResponseEntity<>(null,HttpStatus.OK); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java index 64bcf344..119426a6 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java @@ -67,6 +67,7 @@ public class PlayController { cmder.streamByeCmd(ssrc); StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); + if (streamInfo == null) return new ResponseEntity(HttpStatus.PAYMENT_REQUIRED); storager.stopPlay(streamInfo); if (logger.isDebugEnabled()) { logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc)); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c82e45e7..5b5f01eb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -25,7 +25,6 @@ spring: server: port: 18080 sip: -# ip: 10.200.64.63 ip: 192.168.1.20 port: 5060 # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) @@ -38,4 +37,10 @@ sip: auth: #32位小写md5加密(默认密码为admin) username: admin - password: 21232f297a57a5a743894a0e4a801fc3 \ No newline at end of file + password: 21232f297a57a5a743894a0e4a801fc3 + +media: #zlm服务器的ip与http端口, 重点: 这是http端口 + ip: 192.168.1.20 + port: 9080 + secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc + diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue index 7a1e0e28..7c667baa 100644 --- a/web_src/src/components/channelList.vue +++ b/web_src/src/components/channelList.vue @@ -31,10 +31,19 @@ - + + + +