Commit bd570d167be9671f46ec27568b2a591713897323

Authored by panlinlin
1 parent 1c7f7ef7

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

src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
@@ -92,13 +92,21 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { @@ -92,13 +92,21 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
92 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); 92 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
93 GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId); 93 GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
94 // 不是通道可能是直播流 94 // 不是通道可能是直播流
95 - if (channel != null || gbStream != null ) { 95 + if (channel != null && gbStream == null ) {
96 if (channel.getStatus() == 0) { 96 if (channel.getStatus() == 0) {
97 logger.info("通道离线,返回400"); 97 logger.info("通道离线,返回400");
98 responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline"); 98 responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline");
99 return; 99 return;
100 } 100 }
101 responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 101 responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
  102 + }else if(channel == null && gbStream != null){
  103 + Boolean streamReady = zlmrtpServerFactory.isStreamReady(gbStream.getApp(), gbStream.getStream());
  104 + if (!streamReady) {
  105 + logger.info("[ app={}, stream={} ]通道离线,返回400",gbStream.getApp(), gbStream.getStream());
  106 + responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
  107 + return;
  108 + }
  109 + responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
102 }else { 110 }else {
103 logger.info("通道不存在,返回404"); 111 logger.info("通道不存在,返回404");
104 responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在 112 responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在
@@ -240,34 +248,30 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { @@ -240,34 +248,30 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
240 // 写入redis, 超时时回复 248 // 写入redis, 超时时回复
241 redisCatchStorage.updateSendRTPSever(sendRtpItem); 249 redisCatchStorage.updateSendRTPSever(sendRtpItem);
242 250
243 - // 检测直播流是否在线  
244 - Boolean streamReady = zlmrtpServerFactory.isStreamReady(gbStream.getApp(), gbStream.getStream());  
245 - if (streamReady) {  
246 - sendRtpItem.setStatus(1);  
247 - redisCatchStorage.updateSendRTPSever(sendRtpItem);  
248 - // TODO 添加对tcp的支持  
249 - ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();  
250 - StringBuffer content = new StringBuffer(200);  
251 - content.append("v=0\r\n");  
252 - content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");  
253 - content.append("s=Play\r\n");  
254 - content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");  
255 - content.append("t=0 0\r\n");  
256 - content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");  
257 - content.append("a=sendonly\r\n");  
258 - content.append("a=rtpmap:96 PS/90000\r\n");  
259 - content.append("y="+ ssrc + "\r\n");  
260 - content.append("f=\r\n");  
261 -  
262 - try {  
263 - responseAck(evt, content.toString());  
264 - } catch (SipException e) {  
265 - e.printStackTrace();  
266 - } catch (InvalidArgumentException e) {  
267 - e.printStackTrace();  
268 - } catch (ParseException e) {  
269 - e.printStackTrace();  
270 - } 251 + sendRtpItem.setStatus(1);
  252 + redisCatchStorage.updateSendRTPSever(sendRtpItem);
  253 + // TODO 添加对tcp的支持
  254 + ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
  255 + StringBuffer content = new StringBuffer(200);
  256 + content.append("v=0\r\n");
  257 + content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
  258 + content.append("s=Play\r\n");
  259 + content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");
  260 + content.append("t=0 0\r\n");
  261 + content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
  262 + content.append("a=sendonly\r\n");
  263 + content.append("a=rtpmap:96 PS/90000\r\n");
  264 + content.append("y="+ ssrc + "\r\n");
  265 + content.append("f=\r\n");
  266 +
  267 + try {
  268 + responseAck(evt, content.toString());
  269 + } catch (SipException e) {
  270 + e.printStackTrace();
  271 + } catch (InvalidArgumentException e) {
  272 + e.printStackTrace();
  273 + } catch (ParseException e) {
  274 + e.printStackTrace();
271 } 275 }
272 } 276 }
273 277
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
@@ -16,6 +16,7 @@ public class StreamProxyItem extends GbStream { @@ -16,6 +16,7 @@ public class StreamProxyItem extends GbStream {
16 private boolean enable; 16 private boolean enable;
17 private boolean enable_hls; 17 private boolean enable_hls;
18 private boolean enable_mp4; 18 private boolean enable_mp4;
  19 + private String platformGbId;
19 20
20 public String getType() { 21 public String getType() {
21 return type; 22 return type;
@@ -114,4 +115,11 @@ public class StreamProxyItem extends GbStream { @@ -114,4 +115,11 @@ public class StreamProxyItem extends GbStream {
114 } 115 }
115 116
116 117
  118 + public String getPlatformGbId() {
  119 + return platformGbId;
  120 + }
  121 +
  122 + public void setPlatformGbId(String platformGbId) {
  123 + this.platformGbId = platformGbId;
  124 + }
117 } 125 }
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -59,11 +59,7 @@ public class MediaServiceImpl implements IMediaService { @@ -59,11 +59,7 @@ public class MediaServiceImpl implements IMediaService {
59 JSONArray tracks = mediaJSON.getJSONArray("tracks"); 59 JSONArray tracks = mediaJSON.getJSONArray("tracks");
60 streamInfo = getStreamInfoByAppAndStream(app, stream, tracks); 60 streamInfo = getStreamInfoByAppAndStream(app, stream, tracks);
61 } 61 }
62 -  
63 } 62 }
64 return streamInfo; 63 return streamInfo;
65 } 64 }
66 -  
67 -  
68 -  
69 } 65 }
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
1 package com.genersoft.iot.vmp.service.impl; 1 package com.genersoft.iot.vmp.service.impl;
2 2
3 import com.alibaba.fastjson.JSONObject; 3 import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.gb28181.bean.GbStream;
4 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; 5 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
5 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; 6 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
6 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; 7 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
  8 +import com.genersoft.iot.vmp.service.IGbStreamService;
7 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 9 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
8 import com.genersoft.iot.vmp.storager.IVideoManagerStorager; 10 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
9 import com.genersoft.iot.vmp.storager.dao.GbStreamMapper; 11 import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
@@ -14,6 +16,9 @@ import com.github.pagehelper.PageInfo; @@ -14,6 +16,9 @@ import com.github.pagehelper.PageInfo;
14 import org.springframework.beans.factory.annotation.Autowired; 16 import org.springframework.beans.factory.annotation.Autowired;
15 import org.springframework.stereotype.Service; 17 import org.springframework.stereotype.Service;
16 18
  19 +import java.util.ArrayList;
  20 +import java.util.List;
  21 +
17 /** 22 /**
18 * 视频代理业务 23 * 视频代理业务
19 */ 24 */
@@ -38,6 +43,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -38,6 +43,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
38 @Autowired 43 @Autowired
39 private PlatformGbStreamMapper platformGbStreamMapper; 44 private PlatformGbStreamMapper platformGbStreamMapper;
40 45
  46 + @Autowired
  47 + private IGbStreamService gbStreamService;
  48 +
41 49
42 @Override 50 @Override
43 public String save(StreamProxyItem param) { 51 public String save(StreamProxyItem param) {
@@ -46,6 +54,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -46,6 +54,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
46 param.getStream() ); 54 param.getStream() );
47 param.setDst_url(dstUrl); 55 param.setDst_url(dstUrl);
48 StringBuffer result = new StringBuffer(); 56 StringBuffer result = new StringBuffer();
  57 + boolean streamLive = false;
49 // 更新 58 // 更新
50 if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) { 59 if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) {
51 if (videoManagerStorager.updateStreamProxy(param)) { 60 if (videoManagerStorager.updateStreamProxy(param)) {
@@ -62,9 +71,11 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -62,9 +71,11 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
62 }else { // 新增 71 }else { // 新增
63 if (videoManagerStorager.addStreamProxy(param)){ 72 if (videoManagerStorager.addStreamProxy(param)){
64 result.append("保存成功"); 73 result.append("保存成功");
  74 + streamLive = true;
65 if (param.isEnable()) { 75 if (param.isEnable()) {
66 JSONObject jsonObject = addStreamProxyToZlm(param); 76 JSONObject jsonObject = addStreamProxyToZlm(param);
67 if (jsonObject == null) { 77 if (jsonObject == null) {
  78 + streamLive = false;
68 result.append(", 但是启用失败,请检查流地址是否可用"); 79 result.append(", 但是启用失败,请检查流地址是否可用");
69 param.setEnable(false); 80 param.setEnable(false);
70 videoManagerStorager.updateStreamProxy(param); 81 videoManagerStorager.updateStreamProxy(param);
@@ -73,6 +84,15 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -73,6 +84,15 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
73 } 84 }
74 85
75 } 86 }
  87 + if (param.getPlatformGbId() != null && streamLive) {
  88 + List<GbStream> gbStreams = new ArrayList<>();
  89 + gbStreams.add(param);
  90 + if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId())){
  91 + result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]成功");
  92 + }else {
  93 + result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]失败");
  94 + }
  95 + }
76 return result.toString(); 96 return result.toString();
77 } 97 }
78 98
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
@@ -75,10 +75,15 @@ public class StreamProxyController { @@ -75,10 +75,15 @@ public class StreamProxyController {
75 @ResponseBody 75 @ResponseBody
76 public WVPResult del(String app, String stream){ 76 public WVPResult del(String app, String stream){
77 logger.info("移除代理: " + app + "/" + stream); 77 logger.info("移除代理: " + app + "/" + stream);
78 - streamProxyService.del(app, stream);  
79 WVPResult<Object> result = new WVPResult<>(); 78 WVPResult<Object> result = new WVPResult<>();
80 - result.setCode(0);  
81 - result.setMsg("success"); 79 + if (app == null || stream == null) {
  80 + result.setCode(400);
  81 + result.setMsg(app == null ?"app不能为null":"stream不能为null");
  82 + }else {
  83 + streamProxyService.del(app, stream);
  84 + result.setCode(0);
  85 + result.setMsg("success");
  86 + }
82 return result; 87 return result;
83 } 88 }
84 89
web_src/src/components/ParentPlatformList.vue
@@ -156,7 +156,7 @@ export default { @@ -156,7 +156,7 @@ export default {
156 156
157 this.$axios({ 157 this.$axios({
158 method: 'get', 158 method: 'get',
159 - url:`/api/platform/query/${that.count}/${that.currentPage}` 159 + url:`/api/platform/query/${that.count}/${that.currentPage}`
160 }).then(function (res) { 160 }).then(function (res) {
161 that.total = res.data.total; 161 that.total = res.data.total;
162 that.platformList = res.data.list; 162 that.platformList = res.data.list;
web_src/src/components/StreamProxyList.vue
@@ -33,6 +33,14 @@ @@ -33,6 +33,14 @@
33 </template> 33 </template>
34 </el-table-column> 34 </el-table-column>
35 <el-table-column prop="gbId" label="国标编码" width="180" align="center" show-overflow-tooltip/> 35 <el-table-column prop="gbId" label="国标编码" width="180" align="center" show-overflow-tooltip/>
  36 + <el-table-column label="启用" width="120" align="center">
  37 + <template slot-scope="scope">
  38 + <div slot="reference" class="name-wrapper">
  39 + <el-tag size="medium" v-if="scope.row.enable">已启用</el-tag>
  40 + <el-tag size="medium" type="info" v-if="!scope.row.enable">未启用</el-tag>
  41 + </div>
  42 + </template>
  43 + </el-table-column>
36 <el-table-column label="转HLS" width="120" align="center"> 44 <el-table-column label="转HLS" width="120" align="center">
37 <template slot-scope="scope"> 45 <template slot-scope="scope">
38 <div slot="reference" class="name-wrapper"> 46 <div slot="reference" class="name-wrapper">
@@ -49,14 +57,7 @@ @@ -49,14 +57,7 @@
49 </div> 57 </div>
50 </template> 58 </template>
51 </el-table-column> 59 </el-table-column>
52 - <el-table-column label="启用" width="120" align="center">  
53 - <template slot-scope="scope">  
54 - <div slot="reference" class="name-wrapper">  
55 - <el-tag size="medium" v-if="scope.row.enable">已启用</el-tag>  
56 - <el-tag size="medium" type="info" v-if="!scope.row.enable">未启用</el-tag>  
57 - </div>  
58 - </template>  
59 - </el-table-column> 60 +
60 61
61 <el-table-column label="操作" width="360" align="center" fixed="right"> 62 <el-table-column label="操作" width="360" align="center" fixed="right">
62 <template slot-scope="scope"> 63 <template slot-scope="scope">
web_src/src/components/dialog/StreamProxyEdit.vue
@@ -56,6 +56,22 @@ @@ -56,6 +56,22 @@
56 <el-option label="组播" value="2"></el-option> 56 <el-option label="组播" value="2"></el-option>
57 </el-select> 57 </el-select>
58 </el-form-item> 58 </el-form-item>
  59 + <el-form-item label="国标平台">
  60 + <el-select
  61 + v-model="proxyParam.platformGbId"
  62 + style="width: 100%"
  63 + placeholder="请选择国标平台"
  64 + >
  65 + <el-option
  66 + v-for="item in platformList"
  67 + :key="item.name"
  68 + :label="item.name"
  69 + :value="item.serverGBId">
  70 + <span style="float: left">{{ item.name }}</span>
  71 + <span style="float: right; color: #8492a6; font-size: 13px">{{ item.serverGBId }}</span>
  72 + </el-option>
  73 + </el-select>
  74 + </el-form-item>
59 <el-form-item label="其他选项"> 75 <el-form-item label="其他选项">
60 <div style="float: left;"> 76 <div style="float: left;">
61 <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox> 77 <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox>
@@ -106,6 +122,27 @@ export default { @@ -106,6 +122,27 @@ export default {
106 isLoging: false, 122 isLoging: false,
107 dialogLoading: false, 123 dialogLoading: false,
108 onSubmit_text: "立即创建", 124 onSubmit_text: "立即创建",
  125 + platformList: [{
  126 + id: 1,
  127 + enable: true,
  128 + name: "141",
  129 + serverGBId: "34020000002000000001",
  130 + serverGBDomain: "3402000000",
  131 + serverIP: "192.168.1.141",
  132 + serverPort: 15060,
  133 + deviceGBId: "34020000002000000001",
  134 + deviceIp: "192.168.1.20",
  135 + devicePort: "5060",
  136 + username: "34020000002000000001",
  137 + password: "12345678",
  138 + expires: "300",
  139 + keepTimeout: "60",
  140 + transport: "UDP",
  141 + characterSet: "GB2312",
  142 + ptz: false,
  143 + rtcp: false,
  144 + status: true,
  145 + }],
109 proxyParam: { 146 proxyParam: {
110 name: null, 147 name: null,
111 type: "default", 148 type: "default",
@@ -120,6 +157,7 @@ export default { @@ -120,6 +157,7 @@ export default {
120 enable: true, 157 enable: true,
121 enable_hls: true, 158 enable_hls: true,
122 enable_mp4: false, 159 enable_mp4: false,
  160 + platformGbId: null,
123 }, 161 },
124 162
125 rules: { 163 rules: {
@@ -140,6 +178,17 @@ export default { @@ -140,6 +178,17 @@ export default {
140 if (proxyParam != null) { 178 if (proxyParam != null) {
141 this.proxyParam = proxyParam; 179 this.proxyParam = proxyParam;
142 } 180 }
  181 +
  182 + let that = this;
  183 +
  184 + this.$axios({
  185 + method: 'get',
  186 + url:`/api/platform/query/10000/0`
  187 + }).then(function (res) {
  188 + that.platformList = res.data.list;
  189 + }).catch(function (error) {
  190 + console.log(error);
  191 + });
143 }, 192 },
144 onSubmit: function () { 193 onSubmit: function () {
145 console.log("onSubmit"); 194 console.log("onSubmit");
web_src/src/components/dialog/platformEdit.vue
@@ -105,9 +105,6 @@ export default { @@ -105,9 +105,6 @@ export default {
105 callback(new Error("请输入设备国标编号")); 105 callback(new Error("请输入设备国标编号"));
106 } else { 106 } else {
107 var exit = await this.deviceGBIdExit(value); 107 var exit = await this.deviceGBIdExit(value);
108 - console.log(exit);  
109 - console.log(exit == "true");  
110 - console.log(exit === "true");  
111 if (exit) { 108 if (exit) {
112 callback(new Error("设备国标编号已存在")); 109 callback(new Error("设备国标编号已存在"));
113 } else { 110 } else {