parent
f9ab13a145
commit
fbdad00cdb
|
@ -1,5 +1,7 @@
|
|||
package com.genersoft.iot.vmp.common;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
|
||||
public class StreamInfo {
|
||||
|
||||
private String ssrc;
|
||||
|
@ -10,6 +12,7 @@ public class StreamInfo {
|
|||
private String rtmp;
|
||||
private String hls;
|
||||
private String rtsp;
|
||||
private JSONArray tracks;
|
||||
|
||||
public String getSsrc() {
|
||||
return ssrc;
|
||||
|
@ -74,4 +77,12 @@ public class StreamInfo {
|
|||
public void setCahnnelId(String cahnnelId) {
|
||||
this.cahnnelId = cahnnelId;
|
||||
}
|
||||
|
||||
public JSONArray getTracks() {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
public void setTracks(JSONArray tracks) {
|
||||
this.tracks = tracks;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,9 @@ public class ZLMHttpHookListener {
|
|||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Value("${media.ip}")
|
||||
private String mediaIp;
|
||||
|
||||
|
@ -125,6 +128,8 @@ public class ZLMHttpHookListener {
|
|||
}
|
||||
String app = json.getString("app");
|
||||
String streamId = json.getString("id");
|
||||
|
||||
|
||||
// String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零
|
||||
String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
|
||||
StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
|
||||
|
@ -135,6 +140,8 @@ public class ZLMHttpHookListener {
|
|||
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));
|
||||
|
||||
|
||||
storager.startPlay(streamInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import okhttp3.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class ZLMRESTfulUtils {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ZLMRESTfulUtils.class);
|
||||
|
||||
@Value("${media.ip}")
|
||||
private String mediaIp;
|
||||
|
||||
@Value("${media.port}")
|
||||
private int mediaPort;
|
||||
|
||||
@Value("${media.secret}")
|
||||
private String mediaSecret;
|
||||
|
||||
public JSONObject sendPost(String api, Map<String, Object> param) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
String url = String.format("http://%s:%s/index/api/%s", mediaIp, mediaPort, api);
|
||||
JSONObject responseJSON = null;
|
||||
logger.debug(url);
|
||||
|
||||
FormBody.Builder builder = new FormBody.Builder();
|
||||
builder.add("secret",mediaSecret);
|
||||
if (param != null) {
|
||||
for (String key : param.keySet()){
|
||||
builder.add(key, param.get(key).toString());
|
||||
}
|
||||
}
|
||||
|
||||
FormBody body = builder.build();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.post(body)
|
||||
.url(url)
|
||||
.build();
|
||||
try {
|
||||
Response response = client.newCall(request).execute();
|
||||
if (response.isSuccessful()) {
|
||||
String responseStr = response.body().string();
|
||||
if (responseStr != null) {
|
||||
responseJSON = JSON.parseObject(responseStr);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return responseJSON;
|
||||
}
|
||||
|
||||
public JSONObject getMediaList(String app, String schema){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("app",app);
|
||||
param.put("schema",schema);
|
||||
param.put("vhost","__defaultVhost__");
|
||||
return sendPost("getMediaList",param);
|
||||
}
|
||||
|
||||
public JSONObject getRtpInfo(String stream_id){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("stream_id",stream_id);
|
||||
return sendPost("getRtpInfo",param);
|
||||
}
|
||||
|
||||
public JSONObject getMediaServerConfig(){
|
||||
return sendPost("getServerConfig",null);
|
||||
}
|
||||
|
||||
public JSONObject setServerConfig(Map<String, Object> param){
|
||||
return sendPost("setServerConfig",param);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,8 @@ import org.springframework.stereotype.Component;
|
|||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@Order(value=1)
|
||||
|
@ -42,6 +44,9 @@ public class ZLMRunner implements CommandLineRunner {
|
|||
@Value("${server.port}")
|
||||
private String serverPort;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Override
|
||||
public void run(String... strings) throws Exception {
|
||||
// 获取zlm信息
|
||||
|
@ -59,41 +64,23 @@ public class ZLMRunner implements CommandLineRunner {
|
|||
|
||||
|
||||
public MediaServerConfig getMediaServerConfig() {
|
||||
JSONObject responseJSON = zlmresTfulUtils.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();
|
||||
if (responseJSON != null) {
|
||||
JSONArray data = responseJSON.getJSONArray("data");
|
||||
if (data != null && data.size() > 0) {
|
||||
mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class);
|
||||
mediaServerConfig.setLocalIP(mediaIp);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} else {
|
||||
logger.error("getMediaServerConfig失败, 1s后重试");
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
getMediaServerConfig();
|
||||
}
|
||||
|
||||
return mediaServerConfig;
|
||||
}
|
||||
|
||||
|
@ -102,51 +89,30 @@ public class ZLMRunner implements CommandLineRunner {
|
|||
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);
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("secret",mediaSecret);
|
||||
param.put("hook.enable","1");
|
||||
param.put("hook.on_flow_report","");
|
||||
param.put("hook.on_http_access","");
|
||||
param.put("hook.on_publish",String.format("%s/on_publish", hookPrex));
|
||||
param.put("hook.on_record_mp4","");
|
||||
param.put("hook.on_record_ts","");
|
||||
param.put("hook.on_rtsp_auth","");
|
||||
param.put("hook.on_rtsp_realm","");
|
||||
param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrex));
|
||||
param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex));
|
||||
param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
|
||||
param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
|
||||
param.put("hook.timeoutSec","20");
|
||||
|
||||
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();
|
||||
JSONObject responseJSON = zlmresTfulUtils.setServerConfig(param);
|
||||
|
||||
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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
if (responseJSON != null && responseJSON.getInteger("code") == 0) {
|
||||
logger.info("设置zlm成功");
|
||||
}else {
|
||||
logger.info("设置zlm失败: " + responseJSON.getString("msg"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.genersoft.iot.vmp.vmanager.play;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -31,6 +33,9 @@ public class PlayController {
|
|||
|
||||
@Autowired
|
||||
private IVideoManagerStorager storager;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@GetMapping("/play/{deviceId}/{channelId}")
|
||||
public ResponseEntity<String> play(@PathVariable String deviceId,@PathVariable String channelId){
|
||||
|
@ -38,17 +43,44 @@ public class PlayController {
|
|||
Device device = storager.queryVideoDevice(deviceId);
|
||||
StreamInfo streamInfo = cmder.playStreamCmd(device, channelId);
|
||||
// 等待推流, TODO 默认超时15s
|
||||
|
||||
boolean lockFlag = true;
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (storager.queryPlay(streamInfo) == null || storager.queryPlay(streamInfo).getFlv() == null) {
|
||||
String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
|
||||
|
||||
// 判断推流是否存在
|
||||
while (lockFlag) {
|
||||
try {
|
||||
if (System.currentTimeMillis() - startTime > 15 * 1000)
|
||||
if (System.currentTimeMillis() - startTime > 15 * 1000) {
|
||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
|
||||
if (rtpInfo == null){
|
||||
continue;
|
||||
}else {
|
||||
lockFlag = false;
|
||||
streamInfo = storager.queryPlay(streamInfo);
|
||||
// 获取媒体信息
|
||||
JSONObject mediaList = zlmresTfulUtils.getMediaList("rtp", "rtmp");
|
||||
if (mediaList.getInteger("code") == 0) {
|
||||
JSONArray data = mediaList.getJSONArray("data");
|
||||
if (data!= null) {
|
||||
for (Object datum : data) {
|
||||
JSONObject media = (JSONObject)datum;
|
||||
if (streamId.equals(media.getString("stream"))) {
|
||||
streamInfo.setTracks(media.getJSONArray("tracks"));
|
||||
storager.startPlay(streamInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
streamInfo = storager.queryPlay(streamInfo);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId));
|
||||
logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
|
||||
|
|
|
@ -124,6 +124,18 @@
|
|||
play: function(streamInfo, deviceId, channelId, hasAudio) {
|
||||
console.log(hasAudio);
|
||||
this.hasaudio = hasAudio;
|
||||
// 根据媒体流信息二次判断
|
||||
if( this.hasaudio && !!streamInfo.tracks && streamInfo.tracks.length > 0) {
|
||||
var realHasAudio = false;
|
||||
for (let i = 0; i < streamInfo.tracks; i++) {
|
||||
if (streamInfo.tracks[i].codec_type == 1) { // 判断为音频
|
||||
realHasAudio = true;
|
||||
}
|
||||
}
|
||||
this.hasaudio = realHasAudio && this.hasaudio;
|
||||
}
|
||||
console.log("111")
|
||||
console.log(this.hasaudio)
|
||||
this.ssrc = streamInfo.ssrc;
|
||||
this.deviceId = deviceId;
|
||||
this.channelId = channelId;
|
||||
|
|
Loading…
Reference in New Issue