648540858
2020-10-13 f9ab13a14590d310937de7d78a36ee599dce750b
添加通道音频设置
添加media配置
12个文件已修改
1个文件已添加
257 ■■■■■ 已修改文件
pom.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/channelList.vue 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/gb28181/devicePlayer.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -145,16 +145,19 @@
        </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>
        <!-- okhttp -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.9.0</version>
        </dependency>
    </dependencies>
    
    <build>
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
@@ -143,6 +143,11 @@
     */
    private String  ssrc;
    /**
     *  是否含有音频
     */
    private  boolean hasAudio;
    public String getChannelId() {
        return channelId;
    }
@@ -371,4 +376,16 @@
    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;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -241,13 +241,6 @@
            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);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -200,6 +200,7 @@
                    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);
                }
                // 更新
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java
@@ -2,7 +2,6 @@
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;
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -14,6 +14,7 @@
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 @@
    @Autowired
    private IVideoManagerStorager storager;
    @Value("${media.ip}")
    private String mediaIp;
    @Value("${media.port}")
    private int mediaPort;
    /**
     * 流量统计事件,播放器或推流器断开时并且耗用流量超过特定阈值时会触发此事件,阈值通过配置文件general.flowThreshold配置;此事件对回复不敏感。
     *  
@@ -308,6 +315,7 @@
//        List<MediaServerConfig> 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
        
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
New file
@@ -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"));
                        }
                    }
                }
            }
        });
    }
}
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
@@ -344,6 +344,7 @@
     */
    @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(),
src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
@@ -144,4 +144,10 @@
        PageResult pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count);
        return new ResponseEntity<>(pageResult,HttpStatus.OK);
    }
    @PostMapping("channel/update/{deviceId}")
    public ResponseEntity<PageResult> updateChannel(@PathVariable String deviceId,DeviceChannel channel){
        storager.updateChannel(deviceId, channel);
        return new ResponseEntity<>(null,HttpStatus.OK);
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -67,6 +67,7 @@
        
        cmder.streamByeCmd(ssrc);
        StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
        if (streamInfo == null) return new ResponseEntity<String>(HttpStatus.PAYMENT_REQUIRED);
        storager.stopPlay(streamInfo);
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc));
src/main/resources/application.yml
@@ -25,7 +25,6 @@
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 @@
auth: #32位小写md5加密(默认密码为admin)
    username: admin
    password: 21232f297a57a5a743894a0e4a801fc3
    password: 21232f297a57a5a743894a0e4a801fc3
media: #zlm服务器的ip与http端口, 重点: 这是http端口
    ip: 192.168.1.20
    port: 9080
    secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
web_src/src/components/channelList.vue
@@ -31,10 +31,19 @@
                <el-table ref="channelListTable" :data="deviceChannelList" :height="winHeight" border style="width: 100%">
                    <el-table-column prop="channelId" label="通道编号" width="210">
                        </el-table-column>
                        <el-table-column prop="name" label="通道名称" width="500">
                        <el-table-column prop="name" label="通道名称">
                        </el-table-column>
                        <el-table-column prop="subCount" label="子节点数">
                        </el-table-column>
          <el-table-column label="开启音频" align="center">
            <template slot-scope="scope">
              <el-switch
                @change="updateChannel(scope.row)"
                v-model="scope.row.hasAudio"
                active-color="#409EFF">
              </el-switch>
            </template>
          </el-table-column>
          <el-table-column label="状态" width="180" align="center">
            <template slot-scope="scope">
              <div slot="reference" class="name-wrapper">
@@ -193,6 +202,7 @@
            },
            //通知设备上传媒体流
            sendDevicePush: function(itemData) {
              console.log(itemData)
                let deviceId = this.deviceId;
        this.isLoging = true;
                let channelId = itemData.channelId;
@@ -204,7 +214,7 @@
                }).then(function(res) {
                    let ssrc = res.data.ssrc;
          that.isLoging = false
                    that.$refs.devicePlayer.play(res.data,deviceId,channelId);
                    that.$refs.devicePlayer.play(res.data,deviceId,channelId,itemData.hasAudio);
                }).catch(function(e) {
                });
            },
@@ -256,6 +266,16 @@
                this.currentPage = 1;
                this.total = 0;
                this.initData();
            },
      updateChannel: function(row) {
                console.log(row)
        this.$axios({
          method: 'post',
          url: `/api/channel/update/${this.deviceId}`,
          params: row
        }).then(function(res) {
          console.log(JSON.stringify(res));
        });
            }
        }
web_src/src/components/gb28181/devicePlayer.vue
@@ -1,7 +1,7 @@
<template>
    <div id="devicePlayer">
        <el-dialog title="视频播放" top="0" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="stop()">
      <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" fluent autoplay live stretch></LivePlayer>
      <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :hasaudio="hasaudio" fluent autoplay live ></LivePlayer>
            <div id="shared" style="text-align: right; margin-top: 1rem;">
                <el-tabs v-model="tabActiveName">
                    <el-tab-pane label="媒体流信息" name="media">
@@ -114,17 +114,22 @@
                ssrc: '',
                deviceId: '',
                channelId: '',
                tabActiveName: 'media'
                tabActiveName: 'media',
        hasaudio: false
            };
        },
        methods: {
            play: function(streamInfo, deviceId, channelId) {
            play: function(streamInfo, deviceId, channelId, hasAudio) {
        console.log(hasAudio);
        this.hasaudio = hasAudio;
        this.ssrc = streamInfo.ssrc;
                this.deviceId = deviceId;
                this.channelId = channelId;
                this.videoUrl = streamInfo.flv + "?" + new Date().getTime();
        // this.$refs.videoPlayer.hasaudio = hasAudio;
                // this.videoUrl = streamInfo.flv + "?" + new Date().getTime();
                this.videoUrl = streamInfo.ws_flv;
                this.showVideoDialog = true;
                console.log(this.ssrc);
            },