Commit fbdad00cdb294a857f55e33b2dd92c61dc37475c

Authored by 648540858
1 parent f9ab13a1

修复无音频通道开启通道音频后无法播放的bug

修复点播接口真的收到视频后回复
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
1 1 package com.genersoft.iot.vmp.common;
2 2  
  3 +import com.alibaba.fastjson.JSONArray;
  4 +
3 5 public class StreamInfo {
4 6  
5 7 private String ssrc;
... ... @@ -10,6 +12,7 @@ public class StreamInfo {
10 12 private String rtmp;
11 13 private String hls;
12 14 private String rtsp;
  15 + private JSONArray tracks;
13 16  
14 17 public String getSsrc() {
15 18 return ssrc;
... ... @@ -74,4 +77,12 @@ public class StreamInfo {
74 77 public void setCahnnelId(String cahnnelId) {
75 78 this.cahnnelId = cahnnelId;
76 79 }
  80 +
  81 + public JSONArray getTracks() {
  82 + return tracks;
  83 + }
  84 +
  85 + public void setTracks(JSONArray tracks) {
  86 + this.tracks = tracks;
  87 + }
77 88 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -46,6 +46,9 @@ public class ZLMHttpHookListener {
46 46 @Autowired
47 47 private IVideoManagerStorager storager;
48 48  
  49 + @Autowired
  50 + private ZLMRESTfulUtils zlmresTfulUtils;
  51 +
49 52 @Value("${media.ip}")
50 53 private String mediaIp;
51 54  
... ... @@ -125,6 +128,8 @@ public class ZLMHttpHookListener {
125 128 }
126 129 String app = json.getString("app");
127 130 String streamId = json.getString("id");
  131 +
  132 +
128 133 // String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零
129 134 String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
130 135 StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
... ... @@ -135,6 +140,8 @@ public class ZLMHttpHookListener {
135 140 streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId));
136 141 streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
137 142 streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId));
  143 +
  144 +
138 145 storager.startPlay(streamInfo);
139 146 }
140 147  
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java 0 → 100644
  1 +package com.genersoft.iot.vmp.media.zlm;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONObject;
  5 +import okhttp3.*;
  6 +import org.slf4j.Logger;
  7 +import org.slf4j.LoggerFactory;
  8 +import org.springframework.beans.factory.annotation.Value;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import java.io.IOException;
  12 +import java.util.HashMap;
  13 +import java.util.HashSet;
  14 +import java.util.Map;
  15 +
  16 +@Component
  17 +public class ZLMRESTfulUtils {
  18 +
  19 + private final static Logger logger = LoggerFactory.getLogger(ZLMRESTfulUtils.class);
  20 +
  21 + @Value("${media.ip}")
  22 + private String mediaIp;
  23 +
  24 + @Value("${media.port}")
  25 + private int mediaPort;
  26 +
  27 + @Value("${media.secret}")
  28 + private String mediaSecret;
  29 +
  30 + public JSONObject sendPost(String api, Map<String, Object> param) {
  31 + OkHttpClient client = new OkHttpClient();
  32 + String url = String.format("http://%s:%s/index/api/%s", mediaIp, mediaPort, api);
  33 + JSONObject responseJSON = null;
  34 + logger.debug(url);
  35 +
  36 + FormBody.Builder builder = new FormBody.Builder();
  37 + builder.add("secret",mediaSecret);
  38 + if (param != null) {
  39 + for (String key : param.keySet()){
  40 + builder.add(key, param.get(key).toString());
  41 + }
  42 + }
  43 +
  44 + FormBody body = builder.build();
  45 +
  46 + Request request = new Request.Builder()
  47 + .post(body)
  48 + .url(url)
  49 + .build();
  50 + try {
  51 + Response response = client.newCall(request).execute();
  52 + if (response.isSuccessful()) {
  53 + String responseStr = response.body().string();
  54 + if (responseStr != null) {
  55 + responseJSON = JSON.parseObject(responseStr);
  56 + }
  57 + }
  58 + } catch (IOException e) {
  59 + e.printStackTrace();
  60 + }
  61 +
  62 + return responseJSON;
  63 + }
  64 +
  65 + public JSONObject getMediaList(String app, String schema){
  66 + Map<String, Object> param = new HashMap<>();
  67 + param.put("app",app);
  68 + param.put("schema",schema);
  69 + param.put("vhost","__defaultVhost__");
  70 + return sendPost("getMediaList",param);
  71 + }
  72 +
  73 + public JSONObject getRtpInfo(String stream_id){
  74 + Map<String, Object> param = new HashMap<>();
  75 + param.put("stream_id",stream_id);
  76 + return sendPost("getRtpInfo",param);
  77 + }
  78 +
  79 + public JSONObject getMediaServerConfig(){
  80 + return sendPost("getServerConfig",null);
  81 + }
  82 +
  83 + public JSONObject setServerConfig(Map<String, Object> param){
  84 + return sendPost("setServerConfig",param);
  85 + }
  86 +}
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
... ... @@ -17,6 +17,8 @@ import org.springframework.stereotype.Component;
17 17 import java.io.IOException;
18 18 import java.io.UnsupportedEncodingException;
19 19 import java.net.URLEncoder;
  20 +import java.util.HashMap;
  21 +import java.util.Map;
20 22  
21 23 @Component
22 24 @Order(value=1)
... ... @@ -42,6 +44,9 @@ public class ZLMRunner implements CommandLineRunner {
42 44 @Value("${server.port}")
43 45 private String serverPort;
44 46  
  47 + @Autowired
  48 + private ZLMRESTfulUtils zlmresTfulUtils;
  49 +
45 50 @Override
46 51 public void run(String... strings) throws Exception {
47 52 // 获取zlm信息
... ... @@ -59,41 +64,23 @@ public class ZLMRunner implements CommandLineRunner {
59 64  
60 65  
61 66 public MediaServerConfig getMediaServerConfig() {
  67 + JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig();
62 68 MediaServerConfig mediaServerConfig = null;
63   - OkHttpClient client = new OkHttpClient();
64   - String url = String.format("http://%s:%s/index/api/getServerConfig?secret=%s", mediaIp, mediaPort, mediaSecret);
65   - //创建一个Request
66   - Request request = new Request.Builder()
67   - .get()
68   - .url(url)
69   - .build();
70   - //通过client发起请求
71   - final Call call = client.newCall(request);
72   - //执行同步请求,获取Response对象
73   - Response response = null;
74   - try {
75   - response = call.execute();
76   - if (response.isSuccessful()) {
77   - String responseStr = response.body().string();
78   - if (responseStr != null) {
79   - JSONObject responseJSON = JSON.parseObject(responseStr);
80   - JSONArray data = responseJSON.getJSONArray("data");
81   - if (data != null && data.size() > 0) {
82   - mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class);
83   - mediaServerConfig.setLocalIP(mediaIp);
84   - }
85   - }
86   - }else {
87   - logger.error("getMediaServerConfig失败, 1s后重试");
  69 + if (responseJSON != null) {
  70 + JSONArray data = responseJSON.getJSONArray("data");
  71 + if (data != null && data.size() > 0) {
  72 + mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class);
  73 + mediaServerConfig.setLocalIP(mediaIp);
  74 + }
  75 + } else {
  76 + logger.error("getMediaServerConfig失败, 1s后重试");
  77 + try {
88 78 Thread.sleep(1000);
89   - getMediaServerConfig();
  79 + } catch (InterruptedException e) {
  80 + e.printStackTrace();
90 81 }
91   - } catch (IOException e) {
92   - e.printStackTrace();
93   - } catch (InterruptedException e) {
94   - e.printStackTrace();
  82 + getMediaServerConfig();
95 83 }
96   -
97 84 return mediaServerConfig;
98 85 }
99 86  
... ... @@ -102,51 +89,30 @@ public class ZLMRunner implements CommandLineRunner {
102 89 if (mediaIp.equals(sipIP)) {
103 90 hookIP = "127.0.0.1";
104 91 }
105   - OkHttpClient client = new OkHttpClient();
106   - String url = String.format("http://%s:%s/index/api/setServerConfig", mediaIp, mediaPort);
107   - String hookPrex = String.format("http://%s:%s/index/hook", hookIP, serverPort);
108 92  
109   - RequestBody body = new FormBody.Builder()
110   - .add("secret",mediaSecret)
111   - .add("hook.enable","1")
112   - .add("hook.on_flow_report","")
113   - .add("hook.on_http_access","")
114   - .add("hook.on_publish",String.format("%s/on_publish", hookPrex))
115   - .add("hook.on_record_mp4","")
116   - .add("hook.on_record_ts","")
117   - .add("hook.on_rtsp_auth","")
118   - .add("hook.on_rtsp_realm","")
119   - .add("hook.on_server_started",String.format("%s/on_server_started", hookPrex))
120   - .add("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex))
121   - .add("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex))
122   - .add("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex))
123   - .add("hook.timeoutSec","20")
124   - .build();
125   -
126   - Request request = new Request.Builder()
127   - .post(body)
128   - .url(url)
129   - .build();
130   - client.newCall(request).enqueue(new Callback() {
131   - @Override
132   - public void onFailure(Call call, IOException e) {
133   - logger.error("saveZLMConfig ",e);
134   - }
135   - @Override
136   - public void onResponse(Call call, Response response) throws IOException {
137   - if (response.isSuccessful()) {
138   - String responseStr = response.body().string();
139   - if (responseStr != null) {
140   - JSONObject responseJSON = JSON.parseObject(responseStr);
141   - if (responseJSON.getInteger("code") == 0) {
142   - logger.info("设置zlm成功");
143   - }else {
144   - logger.info("设置zlm失败: " + responseJSON.getString("msg"));
145   - }
146   - }
147   - }
148   -
149   - }
150   - });
  93 + String hookPrex = String.format("http://%s:%s/index/hook", hookIP, serverPort);
  94 + Map<String, Object> param = new HashMap<>();
  95 + param.put("secret",mediaSecret);
  96 + param.put("hook.enable","1");
  97 + param.put("hook.on_flow_report","");
  98 + param.put("hook.on_http_access","");
  99 + param.put("hook.on_publish",String.format("%s/on_publish", hookPrex));
  100 + param.put("hook.on_record_mp4","");
  101 + param.put("hook.on_record_ts","");
  102 + param.put("hook.on_rtsp_auth","");
  103 + param.put("hook.on_rtsp_realm","");
  104 + param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrex));
  105 + param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex));
  106 + param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
  107 + param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
  108 + param.put("hook.timeoutSec","20");
  109 +
  110 + JSONObject responseJSON = zlmresTfulUtils.setServerConfig(param);
  111 +
  112 + if (responseJSON != null && responseJSON.getInteger("code") == 0) {
  113 + logger.info("设置zlm成功");
  114 + }else {
  115 + logger.info("设置zlm失败: " + responseJSON.getString("msg"));
  116 + }
151 117 }
152 118 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
1 1 package com.genersoft.iot.vmp.vmanager.play;
2 2  
3 3 import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONArray;
4 5 import com.genersoft.iot.vmp.common.StreamInfo;
  6 +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
5 7 import org.slf4j.Logger;
6 8 import org.slf4j.LoggerFactory;
7 9 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -31,6 +33,9 @@ public class PlayController {
31 33  
32 34 @Autowired
33 35 private IVideoManagerStorager storager;
  36 +
  37 + @Autowired
  38 + private ZLMRESTfulUtils zlmresTfulUtils;
34 39  
35 40 @GetMapping("/play/{deviceId}/{channelId}")
36 41 public ResponseEntity<String> play(@PathVariable String deviceId,@PathVariable String channelId){
... ... @@ -38,17 +43,44 @@ public class PlayController {
38 43 Device device = storager.queryVideoDevice(deviceId);
39 44 StreamInfo streamInfo = cmder.playStreamCmd(device, channelId);
40 45 // 等待推流, TODO 默认超时15s
41   -
  46 + boolean lockFlag = true;
42 47 long startTime = System.currentTimeMillis();
43   - while (storager.queryPlay(streamInfo) == null || storager.queryPlay(streamInfo).getFlv() == null) {
  48 + String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
  49 +
  50 + // 判断推流是否存在
  51 + while (lockFlag) {
44 52 try {
45   - if (System.currentTimeMillis() - startTime > 15 * 1000)
  53 + if (System.currentTimeMillis() - startTime > 15 * 1000) {
  54 + JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
  55 + if (rtpInfo == null){
  56 + continue;
  57 + }else {
  58 + lockFlag = false;
  59 + streamInfo = storager.queryPlay(streamInfo);
  60 + // 获取媒体信息
  61 + JSONObject mediaList = zlmresTfulUtils.getMediaList("rtp", "rtmp");
  62 + if (mediaList.getInteger("code") == 0) {
  63 + JSONArray data = mediaList.getJSONArray("data");
  64 + if (data!= null) {
  65 + for (Object datum : data) {
  66 + JSONObject media = (JSONObject)datum;
  67 + if (streamId.equals(media.getString("stream"))) {
  68 + streamInfo.setTracks(media.getJSONArray("tracks"));
  69 + storager.startPlay(streamInfo);
  70 + }
  71 + }
  72 + }
  73 + }
  74 + };
  75 +
  76 + }
  77 +
46 78 Thread.sleep(200);
47 79 } catch (InterruptedException e) {
48 80 e.printStackTrace();
49 81 }
50 82 }
51   - streamInfo = storager.queryPlay(streamInfo);
  83 +
52 84 if (logger.isDebugEnabled()) {
53 85 logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId));
54 86 logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
... ...
web_src/src/components/gb28181/devicePlayer.vue
... ... @@ -124,6 +124,18 @@
124 124 play: function(streamInfo, deviceId, channelId, hasAudio) {
125 125 console.log(hasAudio);
126 126 this.hasaudio = hasAudio;
  127 + // 根据媒体流信息二次判断
  128 + if( this.hasaudio && !!streamInfo.tracks && streamInfo.tracks.length > 0) {
  129 + var realHasAudio = false;
  130 + for (let i = 0; i < streamInfo.tracks; i++) {
  131 + if (streamInfo.tracks[i].codec_type == 1) { // 判断为音频
  132 + realHasAudio = true;
  133 + }
  134 + }
  135 + this.hasaudio = realHasAudio && this.hasaudio;
  136 + }
  137 + console.log("111")
  138 + console.log(this.hasaudio)
127 139 this.ssrc = streamInfo.ssrc;
128 140 this.deviceId = deviceId;
129 141 this.channelId = channelId;
... ...