MediaServiceImpl.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package com.genersoft.iot.vmp.service.impl;
  2. import com.genersoft.iot.vmp.common.InviteInfo;
  3. import com.genersoft.iot.vmp.common.InviteSessionType;
  4. import com.genersoft.iot.vmp.common.StreamInfo;
  5. import com.genersoft.iot.vmp.common.VideoManagerConstants;
  6. import com.genersoft.iot.vmp.conf.MediaConfig;
  7. import com.genersoft.iot.vmp.conf.UserSetting;
  8. import com.genersoft.iot.vmp.conf.exception.ControllerException;
  9. import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  10. import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
  11. import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  12. import com.genersoft.iot.vmp.media.bean.MediaInfo;
  13. import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
  14. import com.genersoft.iot.vmp.media.service.IMediaServerService;
  15. import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookListener;
  16. import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
  17. import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  18. import com.genersoft.iot.vmp.media.zlm.dto.HookType;
  19. import com.genersoft.iot.vmp.media.zlm.dto.MediaServer;
  20. import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
  21. import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
  22. import com.genersoft.iot.vmp.media.zlm.dto.hook.HookResultForOnPublish;
  23. import com.genersoft.iot.vmp.service.*;
  24. import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  25. import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  26. import com.genersoft.iot.vmp.utils.DateUtil;
  27. import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  28. import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
  29. import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
  30. import org.slf4j.Logger;
  31. import org.slf4j.LoggerFactory;
  32. import org.springframework.beans.factory.annotation.Autowired;
  33. import org.springframework.data.redis.core.RedisTemplate;
  34. import org.springframework.stereotype.Service;
  35. import org.springframework.util.ObjectUtils;
  36. import java.util.HashMap;
  37. import java.util.List;
  38. import java.util.Map;
  39. @Service
  40. public class MediaServiceImpl implements IMediaService {
  41. private final static Logger logger = LoggerFactory.getLogger(MediaServiceImpl.class);
  42. @Autowired
  43. private IRedisCatchStorage redisCatchStorage;
  44. @Autowired
  45. private IMediaServerService mediaServerService;
  46. @Autowired
  47. private MediaConfig mediaConfig;
  48. @Autowired
  49. private IStreamProxyService streamProxyService;
  50. @Autowired
  51. private UserSetting userSetting;
  52. @Autowired
  53. private RedisTemplate<Object, Object> redisTemplate;
  54. @Autowired
  55. private IUserService userService;
  56. @Autowired
  57. private IInviteStreamService inviteStreamService;
  58. @Autowired
  59. private VideoStreamSessionManager sessionManager;
  60. @Autowired
  61. private IVideoManagerStorage storager;
  62. @Autowired
  63. private ZLMMediaListManager zlmMediaListManager;
  64. @Override
  65. public StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServerItem, String app, String stream, MediaInfo mediaInfo, String callId) {
  66. return getStreamInfoByAppAndStream(mediaServerItem, app, stream, mediaInfo, null, callId, true);
  67. }
  68. @Override
  69. public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr, boolean authority) {
  70. StreamInfo streamInfo = null;
  71. if (mediaServerId == null) {
  72. mediaServerId = mediaConfig.getId();
  73. }
  74. MediaServer mediaInfo = mediaServerService.getOne(mediaServerId);
  75. if (mediaInfo == null) {
  76. return null;
  77. }
  78. String calld = null;
  79. StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
  80. if (streamAuthorityInfo != null) {
  81. calld = streamAuthorityInfo.getCallId();
  82. }
  83. List<StreamInfo> streamInfoList = mediaServerService.getMediaList(mediaInfo, app, stream, calld);
  84. if (streamInfoList.isEmpty()) {
  85. return null;
  86. }else {
  87. return streamInfoList.get(0);
  88. }
  89. }
  90. @Override
  91. public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority) {
  92. return getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, null, authority);
  93. }
  94. @Override
  95. public StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String addr, String callId, boolean isPlay) {
  96. StreamInfo streamInfoResult = new StreamInfo();
  97. streamInfoResult.setStream(stream);
  98. streamInfoResult.setApp(app);
  99. if (addr == null) {
  100. addr = mediaServer.getStreamIp();
  101. }
  102. streamInfoResult.setIp(addr);
  103. streamInfoResult.setMediaServerId(mediaServer.getId());
  104. String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId;
  105. streamInfoResult.setRtmp(addr, mediaServer.getRtmpPort(),mediaServer.getRtmpSSlPort(), app, stream, callIdParam);
  106. streamInfoResult.setRtsp(addr, mediaServer.getRtspPort(),mediaServer.getRtspSSLPort(), app, stream, callIdParam);
  107. streamInfoResult.setFlv(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
  108. streamInfoResult.setFmp4(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
  109. streamInfoResult.setHls(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
  110. streamInfoResult.setTs(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
  111. streamInfoResult.setRtc(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam, isPlay);
  112. streamInfoResult.setMediaInfo(mediaInfo);
  113. return streamInfoResult;
  114. }
  115. @Override
  116. public boolean authenticatePlay(String app, String stream, String callId) {
  117. if (app == null || stream == null) {
  118. return false;
  119. }
  120. if ("rtp".equals(app)) {
  121. return true;
  122. }
  123. StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
  124. return (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(callId));
  125. }
  126. @Override
  127. public ResultForOnPublish authenticatePublish(MediaServer mediaServer, String app, String stream, String params) {
  128. // 推流鉴权的处理
  129. if (!"rtp".equals(app)) {
  130. StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, stream);
  131. if (streamProxyItem != null) {
  132. ResultForOnPublish result = new ResultForOnPublish();
  133. result.setEnable_audio(streamProxyItem.isEnableAudio());
  134. result.setEnable_mp4(streamProxyItem.isEnableMp4());
  135. return result;
  136. }
  137. if (userSetting.getPushAuthority()) {
  138. // 对于推流进行鉴权
  139. Map<String, String> paramMap = urlParamToMap(params);
  140. // 推流鉴权
  141. if (params == null) {
  142. logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)");
  143. throw new ControllerException(ErrorCode.ERROR401.getCode(), "Unauthorized");
  144. }
  145. String sign = paramMap.get("sign");
  146. if (sign == null) {
  147. logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)");
  148. throw new ControllerException(ErrorCode.ERROR401.getCode(), "Unauthorized");
  149. }
  150. // 推流自定义播放鉴权码
  151. String callId = paramMap.get("callId");
  152. // 鉴权配置
  153. boolean hasAuthority = userService.checkPushAuthority(callId, sign);
  154. if (!hasAuthority) {
  155. logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign);
  156. throw new ControllerException(ErrorCode.ERROR401.getCode(), "Unauthorized");
  157. }
  158. StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(app, stream, mediaServer.getId());
  159. streamAuthorityInfo.setCallId(callId);
  160. streamAuthorityInfo.setSign(sign);
  161. // 鉴权通过
  162. redisCatchStorage.updateStreamAuthorityInfo(app, stream, streamAuthorityInfo);
  163. }
  164. } else {
  165. zlmMediaListManager.sendStreamEvent(app, stream, mediaServer.getId());
  166. }
  167. ResultForOnPublish result = new ResultForOnPublish();
  168. result.setEnable_audio(true);
  169. // 是否录像
  170. if ("rtp".equals(app)) {
  171. result.setEnable_mp4(userSetting.getRecordSip());
  172. } else {
  173. result.setEnable_mp4(userSetting.isRecordPushLive());
  174. }
  175. // 国标流
  176. if ("rtp".equals(app)) {
  177. InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, stream);
  178. // 单端口模式下修改流 ID
  179. if (!mediaServer.isRtpEnable() && inviteInfo == null) {
  180. String ssrc = String.format("%010d", Long.parseLong(stream, 16));
  181. inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc);
  182. if (inviteInfo != null) {
  183. result.setStream_replace(inviteInfo.getStream());
  184. logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", stream, inviteInfo.getStream());
  185. }
  186. }
  187. // 设置音频信息及录制信息
  188. List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, stream);
  189. if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) {
  190. // 为录制国标模拟一个鉴权信息, 方便后续写入录像文件时使用
  191. StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(app, stream, mediaServer.getId());
  192. streamAuthorityInfo.setApp(app);
  193. streamAuthorityInfo.setStream(ssrcTransactionForAll.get(0).getStream());
  194. streamAuthorityInfo.setCallId(ssrcTransactionForAll.get(0).getSipTransactionInfo().getCallId());
  195. redisCatchStorage.updateStreamAuthorityInfo(app, ssrcTransactionForAll.get(0).getStream(), streamAuthorityInfo);
  196. String deviceId = ssrcTransactionForAll.get(0).getDeviceId();
  197. String channelId = ssrcTransactionForAll.get(0).getChannelId();
  198. DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
  199. if (deviceChannel != null) {
  200. result.setEnable_audio(deviceChannel.isHasAudio());
  201. }
  202. // 如果是录像下载就设置视频间隔十秒
  203. if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) {
  204. // 获取录像的总时长,然后设置为这个视频的时长
  205. InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream);
  206. if (inviteInfoForDownload != null && inviteInfoForDownload.getStreamInfo() != null) {
  207. String startTime = inviteInfoForDownload.getStreamInfo().getStartTime();
  208. String endTime = inviteInfoForDownload.getStreamInfo().getEndTime();
  209. long difference = DateUtil.getDifference(startTime, endTime) / 1000;
  210. result.setMp4_max_second((int) difference);
  211. result.setEnable_mp4(true);
  212. // 设置为2保证得到的mp4的时长是正常的
  213. result.setModify_stamp(2);
  214. }
  215. }
  216. // 如果是talk对讲,则默认获取声音
  217. if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.TALK) {
  218. result.setEnable_audio(true);
  219. }
  220. }
  221. } else if (app.equals("broadcast")) {
  222. result.setEnable_audio(true);
  223. } else if (app.equals("talk")) {
  224. result.setEnable_audio(true);
  225. }
  226. if (app.equalsIgnoreCase("rtp")) {
  227. String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + stream;
  228. OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo) redisTemplate.opsForValue().get(receiveKey);
  229. String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + stream;
  230. OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo) redisTemplate.opsForValue().get(receiveKeyForPS);
  231. if (otherRtpSendInfo != null || otherPsSendInfo != null) {
  232. result.setEnable_mp4(true);
  233. }
  234. }
  235. return result;
  236. }
  237. private Map<String, String> urlParamToMap(String params) {
  238. HashMap<String, String> map = new HashMap<>();
  239. if (ObjectUtils.isEmpty(params)) {
  240. return map;
  241. }
  242. String[] paramsArray = params.split("&");
  243. if (paramsArray.length == 0) {
  244. return map;
  245. }
  246. for (String param : paramsArray) {
  247. String[] paramArray = param.split("=");
  248. if (paramArray.length == 2) {
  249. map.put(paramArray[0], paramArray[1]);
  250. }
  251. }
  252. return map;
  253. }
  254. }