Browse Source

优化直播流点播流程, 添加流代理接口添加直接关联国标功能

pull/110/head
panlinlin 3 years ago
parent
commit
bd570d167b
  1. 62
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
  2. 8
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
  3. 4
      src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
  4. 20
      src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
  5. 11
      src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
  6. 2
      web_src/src/components/ParentPlatformList.vue
  7. 17
      web_src/src/components/StreamProxyList.vue
  8. 49
      web_src/src/components/dialog/StreamProxyEdit.vue
  9. 3
      web_src/src/components/dialog/platformEdit.vue

62
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java

@ -92,13 +92,21 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId); GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
// 不是通道可能是直播流 // 不是通道可能是直播流
if (channel != null || gbStream != null ) { if (channel != null && gbStream == null ) {
if (channel.getStatus() == 0) { if (channel.getStatus() == 0) {
logger.info("通道离线,返回400"); logger.info("通道离线,返回400");
responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline"); responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline");
return; return;
} }
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
}else if(channel == null && gbStream != null){
Boolean streamReady = zlmrtpServerFactory.isStreamReady(gbStream.getApp(), gbStream.getStream());
if (!streamReady) {
logger.info("[ app={}, stream={} ]通道离线,返回400",gbStream.getApp(), gbStream.getStream());
responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
return;
}
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
}else { }else {
logger.info("通道不存在,返回404"); logger.info("通道不存在,返回404");
responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在 responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在
@ -240,34 +248,30 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
// 写入redis, 超时时回复 // 写入redis, 超时时回复
redisCatchStorage.updateSendRTPSever(sendRtpItem); redisCatchStorage.updateSendRTPSever(sendRtpItem);
// 检测直播流是否在线 sendRtpItem.setStatus(1);
Boolean streamReady = zlmrtpServerFactory.isStreamReady(gbStream.getApp(), gbStream.getStream()); redisCatchStorage.updateSendRTPSever(sendRtpItem);
if (streamReady) { // TODO 添加对tcp的支持
sendRtpItem.setStatus(1); ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
redisCatchStorage.updateSendRTPSever(sendRtpItem); StringBuffer content = new StringBuffer(200);
// TODO 添加对tcp的支持 content.append("v=0\r\n");
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
StringBuffer content = new StringBuffer(200); content.append("s=Play\r\n");
content.append("v=0\r\n"); content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); content.append("t=0 0\r\n");
content.append("s=Play\r\n"); content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); content.append("a=sendonly\r\n");
content.append("t=0 0\r\n"); content.append("a=rtpmap:96 PS/90000\r\n");
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n"); content.append("y="+ ssrc + "\r\n");
content.append("a=sendonly\r\n"); content.append("f=\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("y="+ ssrc + "\r\n"); try {
content.append("f=\r\n"); responseAck(evt, content.toString());
} catch (SipException e) {
try { e.printStackTrace();
responseAck(evt, content.toString()); } catch (InvalidArgumentException e) {
} catch (SipException e) { e.printStackTrace();
e.printStackTrace(); } catch (ParseException e) {
} catch (InvalidArgumentException e) { e.printStackTrace();
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
} }
} }

8
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java

@ -16,6 +16,7 @@ public class StreamProxyItem extends GbStream {
private boolean enable; private boolean enable;
private boolean enable_hls; private boolean enable_hls;
private boolean enable_mp4; private boolean enable_mp4;
private String platformGbId;
public String getType() { public String getType() {
return type; return type;
@ -114,4 +115,11 @@ public class StreamProxyItem extends GbStream {
} }
public String getPlatformGbId() {
return platformGbId;
}
public void setPlatformGbId(String platformGbId) {
this.platformGbId = platformGbId;
}
} }

4
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java

@ -59,11 +59,7 @@ public class MediaServiceImpl implements IMediaService {
JSONArray tracks = mediaJSON.getJSONArray("tracks"); JSONArray tracks = mediaJSON.getJSONArray("tracks");
streamInfo = getStreamInfoByAppAndStream(app, stream, tracks); streamInfo = getStreamInfoByAppAndStream(app, stream, tracks);
} }
} }
return streamInfo; return streamInfo;
} }
} }

20
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java

@ -1,9 +1,11 @@
package com.genersoft.iot.vmp.service.impl; package com.genersoft.iot.vmp.service.impl;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.service.IGbStreamService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper; import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
@ -14,6 +16,9 @@ import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/** /**
* 视频代理业务 * 视频代理业务
*/ */
@ -38,6 +43,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
@Autowired @Autowired
private PlatformGbStreamMapper platformGbStreamMapper; private PlatformGbStreamMapper platformGbStreamMapper;
@Autowired
private IGbStreamService gbStreamService;
@Override @Override
public String save(StreamProxyItem param) { public String save(StreamProxyItem param) {
@ -46,6 +54,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
param.getStream() ); param.getStream() );
param.setDst_url(dstUrl); param.setDst_url(dstUrl);
StringBuffer result = new StringBuffer(); StringBuffer result = new StringBuffer();
boolean streamLive = false;
// 更新 // 更新
if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) { if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) {
if (videoManagerStorager.updateStreamProxy(param)) { if (videoManagerStorager.updateStreamProxy(param)) {
@ -62,9 +71,11 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
}else { // 新增 }else { // 新增
if (videoManagerStorager.addStreamProxy(param)){ if (videoManagerStorager.addStreamProxy(param)){
result.append("保存成功"); result.append("保存成功");
streamLive = true;
if (param.isEnable()) { if (param.isEnable()) {
JSONObject jsonObject = addStreamProxyToZlm(param); JSONObject jsonObject = addStreamProxyToZlm(param);
if (jsonObject == null) { if (jsonObject == null) {
streamLive = false;
result.append(", 但是启用失败,请检查流地址是否可用"); result.append(", 但是启用失败,请检查流地址是否可用");
param.setEnable(false); param.setEnable(false);
videoManagerStorager.updateStreamProxy(param); videoManagerStorager.updateStreamProxy(param);
@ -73,6 +84,15 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
} }
} }
if (param.getPlatformGbId() != null && streamLive) {
List<GbStream> gbStreams = new ArrayList<>();
gbStreams.add(param);
if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId())){
result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]成功");
}else {
result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]失败");
}
}
return result.toString(); return result.toString();
} }

11
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java

@ -75,10 +75,15 @@ public class StreamProxyController {
@ResponseBody @ResponseBody
public WVPResult del(String app, String stream){ public WVPResult del(String app, String stream){
logger.info("移除代理: " + app + "/" + stream); logger.info("移除代理: " + app + "/" + stream);
streamProxyService.del(app, stream);
WVPResult<Object> result = new WVPResult<>(); WVPResult<Object> result = new WVPResult<>();
result.setCode(0); if (app == null || stream == null) {
result.setMsg("success"); result.setCode(400);
result.setMsg(app == null ?"app不能为null":"stream不能为null");
}else {
streamProxyService.del(app, stream);
result.setCode(0);
result.setMsg("success");
}
return result; return result;
} }

2
web_src/src/components/ParentPlatformList.vue

@ -156,7 +156,7 @@ export default {
this.$axios({ this.$axios({
method: 'get', method: 'get',
url:`/api/platform/query/${that.count}/${that.currentPage}` url:`/api/platform/query/${that.count}/${that.currentPage}`
}).then(function (res) { }).then(function (res) {
that.total = res.data.total; that.total = res.data.total;
that.platformList = res.data.list; that.platformList = res.data.list;

17
web_src/src/components/StreamProxyList.vue

@ -33,6 +33,14 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="gbId" label="国标编码" width="180" align="center" show-overflow-tooltip/> <el-table-column prop="gbId" label="国标编码" width="180" align="center" show-overflow-tooltip/>
<el-table-column label="启用" width="120" align="center">
<template slot-scope="scope">
<div slot="reference" class="name-wrapper">
<el-tag size="medium" v-if="scope.row.enable">已启用</el-tag>
<el-tag size="medium" type="info" v-if="!scope.row.enable">未启用</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="转HLS" width="120" align="center"> <el-table-column label="转HLS" width="120" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<div slot="reference" class="name-wrapper"> <div slot="reference" class="name-wrapper">
@ -49,14 +57,7 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="启用" width="120" align="center">
<template slot-scope="scope">
<div slot="reference" class="name-wrapper">
<el-tag size="medium" v-if="scope.row.enable">已启用</el-tag>
<el-tag size="medium" type="info" v-if="!scope.row.enable">未启用</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="360" align="center" fixed="right"> <el-table-column label="操作" width="360" align="center" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">

49
web_src/src/components/dialog/StreamProxyEdit.vue

@ -56,6 +56,22 @@
<el-option label="组播" value="2"></el-option> <el-option label="组播" value="2"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="国标平台">
<el-select
v-model="proxyParam.platformGbId"
style="width: 100%"
placeholder="请选择国标平台"
>
<el-option
v-for="item in platformList"
:key="item.name"
:label="item.name"
:value="item.serverGBId">
<span style="float: left">{{ item.name }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.serverGBId }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="其他选项"> <el-form-item label="其他选项">
<div style="float: left;"> <div style="float: left;">
<el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox> <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox>
@ -106,6 +122,27 @@ export default {
isLoging: false, isLoging: false,
dialogLoading: false, dialogLoading: false,
onSubmit_text: "立即创建", onSubmit_text: "立即创建",
platformList: [{
id: 1,
enable: true,
name: "141",
serverGBId: "34020000002000000001",
serverGBDomain: "3402000000",
serverIP: "192.168.1.141",
serverPort: 15060,
deviceGBId: "34020000002000000001",
deviceIp: "192.168.1.20",
devicePort: "5060",
username: "34020000002000000001",
password: "12345678",
expires: "300",
keepTimeout: "60",
transport: "UDP",
characterSet: "GB2312",
ptz: false,
rtcp: false,
status: true,
}],
proxyParam: { proxyParam: {
name: null, name: null,
type: "default", type: "default",
@ -120,6 +157,7 @@ export default {
enable: true, enable: true,
enable_hls: true, enable_hls: true,
enable_mp4: false, enable_mp4: false,
platformGbId: null,
}, },
rules: { rules: {
@ -140,6 +178,17 @@ export default {
if (proxyParam != null) { if (proxyParam != null) {
this.proxyParam = proxyParam; this.proxyParam = proxyParam;
} }
let that = this;
this.$axios({
method: 'get',
url:`/api/platform/query/10000/0`
}).then(function (res) {
that.platformList = res.data.list;
}).catch(function (error) {
console.log(error);
});
}, },
onSubmit: function () { onSubmit: function () {
console.log("onSubmit"); console.log("onSubmit");

3
web_src/src/components/dialog/platformEdit.vue

@ -105,9 +105,6 @@ export default {
callback(new Error("请输入设备国标编号")); callback(new Error("请输入设备国标编号"));
} else { } else {
var exit = await this.deviceGBIdExit(value); var exit = await this.deviceGBIdExit(value);
console.log(exit);
console.log(exit == "true");
console.log(exit === "true");
if (exit) { if (exit) {
callback(new Error("设备国标编号已存在")); callback(new Error("设备国标编号已存在"));
} else { } else {

Loading…
Cancel
Save