Merge remote-tracking branch 'origin/wvp-28181-2.0' into commercial

# Conflicts:
#	sql/update.sql
#	src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
#	web_src/src/components/dialog/deviceEdit.vue
#	web_src/src/components/dialog/devicePlayer.vue
This commit is contained in:
648540858
2022-06-27 10:16:21 +08:00
106 changed files with 3638 additions and 1447 deletions

View File

@@ -11,7 +11,6 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.media.zlm.dto.*;
import com.genersoft.iot.vmp.service.*;
@@ -92,10 +91,9 @@ public class ZLMHttpHookListener {
public ResponseEntity<String> onServerKeepalive(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("[ ZLM HOOK ]on_server_keepalive API调用参数" + json.toString());
logger.debug("[ ZLM HOOK ] on_server_keepalive API调用参数" + json.toString());
}
String mediaServerId = json.getString("mediaServerId");
List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_keepalive);
if (subscribes != null && subscribes.size() > 0) {
for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
@@ -165,7 +163,6 @@ public class ZLMHttpHookListener {
if (mediaInfo != null) {
subscribe.response(mediaInfo, json);
}
}
JSONObject ret = new JSONObject();
ret.put("code", 0);
@@ -248,6 +245,23 @@ public class ZLMHttpHookListener {
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
/**
* 录制hls完成后通知事件此事件对回复不敏感。
*
*/
@ResponseBody
@PostMapping(value = "/on_record_ts", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onRecordTs(@RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("[ ZLM HOOK ]on_record_ts API调用参数" + json.toString());
}
String mediaServerId = json.getString("mediaServerId");
JSONObject ret = new JSONObject();
ret.put("code", 0);
ret.put("msg", "success");
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
}
/**
* rtsp专用的鉴权事件先触发on_rtsp_realm事件然后才会触发on_rtsp_auth事件。
@@ -383,21 +397,22 @@ public class ZLMHttpHookListener {
if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal()
|| item.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|| item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) {
streamPushItem = zlmMediaListManager.addPush(item);
item.setSeverId(userSetting.getServerId());
zlmMediaListManager.addPush(item);
}
List<GbStream> gbStreams = new ArrayList<>();
if (streamPushItem == null || streamPushItem.getGbId() == null) {
GbStream gbStream = storager.getGbStream(app, streamId);
gbStreams.add(gbStream);
}else {
if (streamPushItem.getGbId() != null) {
gbStreams.add(streamPushItem);
}
}
if (gbStreams.size() > 0) {
// List<GbStream> gbStreams = new ArrayList<>();
// if (streamPushItem == null || streamPushItem.getGbId() == null) {
// GbStream gbStream = storager.getGbStream(app, streamId);
// gbStreams.add(gbStream);
// }else {
// if (streamPushItem.getGbId() != null) {
// gbStreams.add(streamPushItem);
// }
// }
// if (gbStreams.size() > 0) {
// eventPublisher.catalogEventPublishForStream(null, gbStreams, CatalogEvent.ON);
}
// }
}else {
// 兼容流注销时类型从redis记录获取

View File

@@ -24,6 +24,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author lin
*/
@Component
public class ZLMMediaListManager {
@@ -147,7 +150,6 @@ public class ZLMMediaListManager {
}
}
}
// StreamProxyItem streamProxyItem = gbStreamMapper.selectOne(transform.getApp(), transform.getStream());
List<GbStream> gbStreamList = gbStreamMapper.selectByGBId(transform.getGbId());
if (gbStreamList != null && gbStreamList.size() == 1) {
transform.setGbStreamId(gbStreamList.get(0).getGbStreamId());
@@ -162,13 +164,12 @@ public class ZLMMediaListManager {
}
if (transform != null) {
if (channelOnlineEvents.get(transform.getGbId()) != null) {
channelOnlineEvents.get(transform.getGbId()).run(transform.getApp(), transform.getStream());
channelOnlineEvents.get(transform.getGbId()).run(transform.getApp(), transform.getStream(), transform.getServerId());
channelOnlineEvents.remove(transform.getGbId());
}
}
}
storager.updateMedia(transform);
return transform;
}

View File

@@ -12,6 +12,7 @@ import org.springframework.stereotype.Component;
import java.io.*;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -28,6 +29,9 @@ public class ZLMRESTfulUtils {
private OkHttpClient getClient(){
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
//todo 暂时写死超时时间 均为5s
httpClientBuilder.connectTimeout(5,TimeUnit.SECONDS); //设置连接超时时间
httpClientBuilder.readTimeout(5,TimeUnit.SECONDS); //设置读取超时时间
if (logger.isDebugEnabled()) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> {
logger.debug("http请求参数" + message);
@@ -47,7 +51,10 @@ public class ZLMRESTfulUtils {
return null;
}
String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
JSONObject responseJSON = null;
JSONObject responseJSON = new JSONObject();
//-2自定义流媒体 调用错误码
responseJSON.put("code",-2);
responseJSON.put("msg","流媒体调用失败");
FormBody.Builder builder = new FormBody.Builder();
builder.add("secret",mediaServerItem.getSecret());
@@ -78,11 +85,20 @@ public class ZLMRESTfulUtils {
response.close();
Objects.requireNonNull(response.body()).close();
}
} catch (ConnectException e) {
logger.error(String.format("连接ZLM失败: %s, %s", e.getCause().getMessage(), e.getMessage()));
logger.info("请检查media配置并确认ZLM已启动...");
}catch (IOException e) {
logger.error(String.format("[ %s ]请求失败: %s", url, e.getMessage()));
if(e instanceof SocketTimeoutException){
//读取超时超时异常
logger.error(String.format("读取ZLM数据失败: %s, %s", url, e.getMessage()));
}
if(e instanceof ConnectException){
//判断连接异常我这里是报Failed to connect to 10.7.5.144
logger.error(String.format("连接ZLM失败: %s, %s", url, e.getMessage()));
}
}catch (Exception e){
logger.error(String.format("访问ZLM失败: %s, %s", url, e.getMessage()));
}
}else {
client.newCall(request).enqueue(new Callback(){
@@ -105,8 +121,16 @@ public class ZLMRESTfulUtils {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
logger.error(String.format("连接ZLM失败: %s, %s", e.getCause().getMessage(), e.getMessage()));
logger.info("请检查media配置并确认ZLM已启动...");
logger.error(String.format("连接ZLM失败: %s, %s", call.request().toString(), e.getMessage()));
if(e instanceof SocketTimeoutException){
//读取超时超时异常
logger.error(String.format("读取ZLM数据失败: %s, %s", call.request().toString(), e.getMessage()));
}
if(e instanceof ConnectException){
//判断连接异常我这里是报Failed to connect to 10.7.5.144
logger.error(String.format("连接ZLM失败: %s, %s", call.request().toString(), e.getMessage()));
}
}
});
}
@@ -151,7 +175,7 @@ public class ZLMRESTfulUtils {
}
}
File snapFile = new File(targetPath + "/" + fileName);
File snapFile = new File(targetPath + File.separator + fileName);
FileOutputStream outStream = new FileOutputStream(snapFile);
outStream.write(Objects.requireNonNull(response.body()).bytes());

View File

@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import org.slf4j.Logger;
@@ -20,6 +21,9 @@ public class ZLMRTPServerFactory {
@Autowired
private ZLMRESTfulUtils zlmresTfulUtils;
@Autowired
private UserSetting userSetting;
private int[] portRangeArray = new int[2];
public int getFreePort(MediaServerItem mediaServerItem, int startPort, int endPort, List<Integer> usedFreelist) {
@@ -87,10 +91,15 @@ public class ZLMRTPServerFactory {
int result = -1;
// 查询此rtp server 是否已经存在
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
if (rtpInfo != null && rtpInfo.getInteger("code") == 0 && rtpInfo.getBoolean("exist")) {
result = rtpInfo.getInteger("local_port");
if(rtpInfo.getInteger("code") == 0){
if (rtpInfo.getBoolean("exist")) {
result = rtpInfo.getInteger("local_port");
return result;
}
}else if(rtpInfo.getInteger("code") == -2){
return result;
}
Map<String, Object> param = new HashMap<>();
// 推流端口设置0则使用随机端口
param.put("enable_tcp", 1);
@@ -197,6 +206,7 @@ public class ZLMRTPServerFactory {
sendRtpItem.setTcp(tcp);
sendRtpItem.setApp("rtp");
sendRtpItem.setLocalPort(localPort);
sendRtpItem.setServerId(userSetting.getServerId());
sendRtpItem.setMediaServerId(serverItem.getId());
return sendRtpItem;
}
@@ -238,6 +248,7 @@ public class ZLMRTPServerFactory {
sendRtpItem.setChannelId(channelId);
sendRtpItem.setTcp(tcp);
sendRtpItem.setLocalPort(localPort);
sendRtpItem.setServerId(userSetting.getServerId());
sendRtpItem.setMediaServerId(serverItem.getId());
return sendRtpItem;
}
@@ -279,10 +290,10 @@ public class ZLMRTPServerFactory {
*/
public int totalReaderCount(MediaServerItem mediaServerItem, String app, String streamId) {
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
Integer code = mediaInfo.getInteger("code");
if (mediaInfo == null) {
return 0;
}
Integer code = mediaInfo.getInteger("code");
if ( code < 0) {
logger.warn("查询流({}/{})是否有其它观看者时得到: {}", app, streamId, mediaInfo.getString("msg"));
return -1;

View File

@@ -1,6 +1,9 @@
package com.genersoft.iot.vmp.media.zlm.dto;
/**
* @author lin
*/
public interface ChannelOnlineEvent {
void run(String app, String stream);
void run(String app, String stream, String serverId);
}

View File

@@ -61,10 +61,15 @@ public class MediaItem {
private String originUrl;
/**
* 服务器id
* 流媒体服务器id
*/
private String mediaServerId;
/**
* 服务器id
*/
private String severId;
/**
* GMT unix系统时间戳单位秒
*/
@@ -414,4 +419,12 @@ public class MediaItem {
public void setStreamInfo(StreamInfo streamInfo) {
this.streamInfo = streamInfo;
}
public String getSeverId() {
return severId;
}
public void setSeverId(String severId) {
this.severId = severId;
}
}

View File

@@ -81,6 +81,11 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte
*/
private String mediaServerId;
/**
* 使用的服务ID
*/
private String serverId;
public String getVhost() {
return vhost;
}
@@ -219,5 +224,13 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte
public void setMediaServerId(String mediaServerId) {
this.mediaServerId = mediaServerId;
}
public String getServerId() {
return serverId;
}
public void setServerId(String serverId) {
this.serverId = serverId;
}
}

View File

@@ -61,13 +61,12 @@ public class ZLMKeepliveTimeoutListener extends RedisKeyExpirationEventMessageLi
// 发起http请求验证zlm是否确实无法连接如果确实无法连接则发送离线事件否则不作处理
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
JSONObject mediaServerConfig = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
if (mediaServerConfig == null) {
publisher.zlmOfflineEventPublish(mediaServerId);
}else {
if (mediaServerConfig != null && mediaServerConfig.getInteger("code") == 0) {
logger.info("[zlm心跳到期]{}验证后zlm仍在线恢复心跳信息", mediaServerId);
// 添加zlm信息
mediaServerService.updateMediaServerKeepalive(mediaServerId, mediaServerConfig);
}else {
publisher.zlmOfflineEventPublish(mediaServerId);
}
}
}

View File

@@ -42,7 +42,7 @@ public class ZLMStatusEventListener {
logger.info("[ZLM] 上线 ID" + event.getMediaServerId());
streamPushService.zlmServerOnline(event.getMediaServerId());
streamProxyService.zlmServerOnline(event.getMediaServerId());
playService.zlmServerOnline(event.getMediaServerId());
}
@Async