ZLMMediaNodeServerService.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. package com.genersoft.iot.vmp.media.zlm;
  2. import com.alibaba.fastjson2.JSON;
  3. import com.alibaba.fastjson2.JSONArray;
  4. import com.alibaba.fastjson2.JSONObject;
  5. import com.genersoft.iot.vmp.common.CommonCallback;
  6. import com.genersoft.iot.vmp.common.StreamInfo;
  7. import com.genersoft.iot.vmp.conf.exception.ControllerException;
  8. import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  9. import com.genersoft.iot.vmp.media.bean.MediaInfo;
  10. import com.genersoft.iot.vmp.media.service.IMediaNodeServerService;
  11. import com.genersoft.iot.vmp.media.bean.MediaServer;
  12. import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig;
  13. import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  14. import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
  15. import org.slf4j.Logger;
  16. import org.slf4j.LoggerFactory;
  17. import org.springframework.beans.factory.annotation.Autowired;
  18. import org.springframework.beans.factory.annotation.Value;
  19. import org.springframework.stereotype.Service;
  20. import org.springframework.util.ObjectUtils;
  21. import java.util.ArrayList;
  22. import java.util.HashMap;
  23. import java.util.List;
  24. import java.util.Map;
  25. @Service("zlm")
  26. public class ZLMMediaNodeServerService implements IMediaNodeServerService {
  27. private final static Logger logger = LoggerFactory.getLogger(ZLMMediaNodeServerService.class);
  28. @Autowired
  29. private ZLMRESTfulUtils zlmresTfulUtils;
  30. @Autowired
  31. private ZLMServerFactory zlmServerFactory;
  32. @Value("${sip.ip}")
  33. private String sipIp;
  34. @Override
  35. public int createRTPServer(MediaServer mediaServer, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean disableAudio, Boolean reUsePort, Integer tcpMode) {
  36. return zlmServerFactory.createRTPServer(mediaServer, streamId, ssrc, port, onlyAuto, reUsePort, tcpMode);
  37. }
  38. @Override
  39. public void closeRtpServer(MediaServer mediaServer, String streamId) {
  40. zlmServerFactory.closeRtpServer(mediaServer, streamId);
  41. }
  42. @Override
  43. public void closeRtpServer(MediaServer mediaServer, String streamId, CommonCallback<Boolean> callback) {
  44. zlmServerFactory.closeRtpServer(mediaServer, streamId, callback);
  45. }
  46. @Override
  47. public void closeStreams(MediaServer mediaServer, String app, String stream) {
  48. zlmresTfulUtils.closeStreams(mediaServer, app, stream);
  49. }
  50. @Override
  51. public Boolean updateRtpServerSSRC(MediaServer mediaServer, String streamId, String ssrc) {
  52. return zlmServerFactory.updateRtpServerSSRC(mediaServer, streamId, ssrc);
  53. }
  54. @Override
  55. public boolean checkNodeId(MediaServer mediaServer) {
  56. if (mediaServer == null) {
  57. return false;
  58. }
  59. JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServer);
  60. if (responseJSON != null) {
  61. JSONArray data = responseJSON.getJSONArray("data");
  62. if (data != null && !data.isEmpty()) {
  63. ZLMServerConfig zlmServerConfig= JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
  64. return zlmServerConfig.getGeneralMediaServerId().equals(mediaServer.getId());
  65. }else {
  66. return false;
  67. }
  68. }else {
  69. return false;
  70. }
  71. }
  72. @Override
  73. public void online(MediaServer mediaServer) {
  74. }
  75. @Override
  76. public MediaServer checkMediaServer(String ip, int port, String secret) {
  77. MediaServer mediaServer = new MediaServer();
  78. mediaServer.setIp(ip);
  79. mediaServer.setHttpPort(port);
  80. mediaServer.setFlvPort(port);
  81. mediaServer.setWsFlvPort(port);
  82. mediaServer.setSecret(secret);
  83. JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServer);
  84. if (responseJSON == null) {
  85. throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接失败");
  86. }
  87. JSONArray data = responseJSON.getJSONArray("data");
  88. if (data == null) {
  89. throw new ControllerException(ErrorCode.ERROR100.getCode(), "读取配置失败");
  90. }
  91. ZLMServerConfig zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
  92. if (zlmServerConfig == null) {
  93. throw new ControllerException(ErrorCode.ERROR100.getCode(), "读取配置失败");
  94. }
  95. mediaServer.setId(zlmServerConfig.getGeneralMediaServerId());
  96. mediaServer.setHttpSSlPort(zlmServerConfig.getHttpPort());
  97. mediaServer.setFlvSSLPort(zlmServerConfig.getHttpPort());
  98. mediaServer.setWsFlvSSLPort(zlmServerConfig.getHttpPort());
  99. mediaServer.setRtmpPort(zlmServerConfig.getRtmpPort());
  100. mediaServer.setRtmpSSlPort(zlmServerConfig.getRtmpSslPort());
  101. mediaServer.setRtspPort(zlmServerConfig.getRtspPort());
  102. mediaServer.setRtspSSLPort(zlmServerConfig.getRtspSSlport());
  103. mediaServer.setRtpProxyPort(zlmServerConfig.getRtpProxyPort());
  104. mediaServer.setStreamIp(ip);
  105. mediaServer.setHookIp(sipIp.split(",")[0]);
  106. mediaServer.setSdpIp(ip);
  107. mediaServer.setType("zlm");
  108. return mediaServer;
  109. }
  110. @Override
  111. public boolean stopSendRtp(MediaServer mediaInfo, String app, String stream, String ssrc) {
  112. Map<String, Object> param = new HashMap<>();
  113. param.put("vhost", "__defaultVhost__");
  114. param.put("app", app);
  115. param.put("stream", stream);
  116. if (!ObjectUtils.isEmpty(ssrc)) {
  117. param.put("ssrc", ssrc);
  118. }
  119. JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaInfo, param);
  120. if (jsonObject == null || jsonObject.getInteger("code") != 0 ) {
  121. logger.error("停止发流失败: {}, 参数:{}", jsonObject.getString("msg"), JSON.toJSONString(param));
  122. throw new ControllerException(jsonObject.getInteger("code"), jsonObject.getString("msg"));
  123. }
  124. return true;
  125. }
  126. @Override
  127. public boolean deleteRecordDirectory(MediaServer mediaServer, String app, String stream, String date, String fileName) {
  128. logger.info("[zlm-deleteRecordDirectory] 删除磁盘文件, server: {} {}:{}->{}/{}", mediaServer.getId(), app, stream, date, fileName);
  129. JSONObject jsonObject = zlmresTfulUtils.deleteRecordDirectory(mediaServer, app,
  130. stream, date, fileName);
  131. if (jsonObject.getInteger("code") == 0) {
  132. return true;
  133. }else {
  134. logger.info("[zlm-deleteRecordDirectory] 删除磁盘文件错误, server: {} {}:{}->{}/{}, 结果: {}", mediaServer.getId(), app, stream, date, fileName, jsonObject);
  135. return false;
  136. }
  137. }
  138. @Override
  139. public List<StreamInfo> getMediaList(MediaServer mediaServer, String app, String stream, String callId) {
  140. List<StreamInfo> streamInfoList = new ArrayList<>();
  141. JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaServer, app, stream);
  142. if (mediaList != null) {
  143. if (mediaList.getInteger("code") == 0) {
  144. JSONArray data = mediaList.getJSONArray("data");
  145. if (data == null) {
  146. return null;
  147. }
  148. JSONObject mediaJSON = data.getJSONObject(0);
  149. MediaInfo mediaInfo = MediaInfo.getInstance(mediaJSON, mediaServer);
  150. StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, app, stream, mediaInfo, callId, true);
  151. if (streamInfo != null) {
  152. streamInfoList.add(streamInfo);
  153. }
  154. }
  155. }
  156. return streamInfoList;
  157. }
  158. public StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String callId, boolean isPlay) {
  159. StreamInfo streamInfoResult = new StreamInfo();
  160. streamInfoResult.setStream(stream);
  161. streamInfoResult.setApp(app);
  162. String addr = mediaServer.getStreamIp();
  163. streamInfoResult.setIp(addr);
  164. streamInfoResult.setMediaServerId(mediaServer.getId());
  165. String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId;
  166. streamInfoResult.setRtmp(addr, mediaServer.getRtmpPort(),mediaServer.getRtmpSSlPort(), app, stream, callIdParam);
  167. streamInfoResult.setRtsp(addr, mediaServer.getRtspPort(),mediaServer.getRtspSSLPort(), app, stream, callIdParam);
  168. String flvFile = String.format("%s/%s.live.flv%s", app, stream, callIdParam);
  169. streamInfoResult.setFlv(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), flvFile);
  170. streamInfoResult.setWsFlv(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), flvFile);
  171. streamInfoResult.setFmp4(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
  172. streamInfoResult.setHls(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
  173. streamInfoResult.setTs(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam);
  174. streamInfoResult.setRtc(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam, isPlay);
  175. streamInfoResult.setMediaInfo(mediaInfo);
  176. streamInfoResult.setOriginType(mediaInfo.getOriginType());
  177. return streamInfoResult;
  178. }
  179. @Override
  180. public Boolean connectRtpServer(MediaServer mediaServer, String address, int port, String stream) {
  181. JSONObject jsonObject = zlmresTfulUtils.connectRtpServer(mediaServer, address, port, stream);
  182. logger.info("[TCP主动连接对方] 结果: {}", jsonObject);
  183. return jsonObject.getInteger("code") == 0;
  184. }
  185. @Override
  186. public void getSnap(MediaServer mediaServer, String streamUrl, int timeoutSec, int expireSec, String path, String fileName) {
  187. zlmresTfulUtils.getSnap(mediaServer, streamUrl, timeoutSec, expireSec, path, fileName);
  188. }
  189. @Override
  190. public MediaInfo getMediaInfo(MediaServer mediaServer, String app, String stream) {
  191. JSONObject jsonObject = zlmresTfulUtils.getMediaInfo(mediaServer, app, "rtsp", stream);
  192. if (jsonObject.getInteger("code") != 0) {
  193. return null;
  194. }
  195. return MediaInfo.getInstance(jsonObject, mediaServer);
  196. }
  197. @Override
  198. public Boolean pauseRtpCheck(MediaServer mediaServer, String streamKey) {
  199. JSONObject jsonObject = zlmresTfulUtils.pauseRtpCheck(mediaServer, streamKey);
  200. return jsonObject.getInteger("code") == 0;
  201. }
  202. @Override
  203. public Boolean resumeRtpCheck(MediaServer mediaServer, String streamKey) {
  204. JSONObject jsonObject = zlmresTfulUtils.resumeRtpCheck(mediaServer, streamKey);
  205. return jsonObject.getInteger("code") == 0;
  206. }
  207. @Override
  208. public String getFfmpegCmd(MediaServer mediaServer, String cmdKey) {
  209. JSONObject jsonObject = zlmresTfulUtils.getMediaServerConfig(mediaServer);
  210. if (jsonObject.getInteger("code") != 0) {
  211. logger.warn("[getFfmpegCmd] 获取流媒体配置失败");
  212. throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取流媒体配置失败");
  213. }
  214. JSONArray dataArray = jsonObject.getJSONArray("data");
  215. JSONObject mediaServerConfig = dataArray.getJSONObject(0);
  216. if (ObjectUtils.isEmpty(cmdKey)) {
  217. cmdKey = "ffmpeg.cmd";
  218. }
  219. return mediaServerConfig.getString(cmdKey);
  220. }
  221. @Override
  222. public WVPResult<String> addFFmpegSource(MediaServer mediaServer, String srcUrl, String dstUrl, int timeoutMs, boolean enableAudio, boolean enableMp4, String ffmpegCmdKey) {
  223. JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(mediaServer, srcUrl, dstUrl, timeoutMs, enableAudio, enableMp4, ffmpegCmdKey);
  224. if (jsonObject.getInteger("code") != 0) {
  225. logger.warn("[getFfmpegCmd] 添加FFMPEG代理失败");
  226. return WVPResult.fail(ErrorCode.ERROR100.getCode(), "添加FFMPEG代理失败");
  227. }else {
  228. JSONObject data = jsonObject.getJSONObject("data");
  229. if (data == null) {
  230. return WVPResult.fail(ErrorCode.ERROR100.getCode(), "代理结果异常: " + jsonObject);
  231. }else {
  232. return WVPResult.success(data.getString("key"));
  233. }
  234. }
  235. }
  236. @Override
  237. public WVPResult<String> addStreamProxy(MediaServer mediaServer, String app, String stream, String url, boolean enableAudio, boolean enableMp4, String rtpType) {
  238. JSONObject jsonObject = zlmresTfulUtils.addStreamProxy(mediaServer, app, stream, url, enableAudio, enableMp4, rtpType);
  239. if (jsonObject.getInteger("code") != 0) {
  240. return WVPResult.fail(ErrorCode.ERROR100.getCode(), "添加代理失败");
  241. }else {
  242. JSONObject data = jsonObject.getJSONObject("data");
  243. if (data == null) {
  244. return WVPResult.fail(ErrorCode.ERROR100.getCode(), "代理结果异常: " + jsonObject);
  245. }else {
  246. return WVPResult.success(data.getString("key"));
  247. }
  248. }
  249. }
  250. @Override
  251. public Boolean delFFmpegSource(MediaServer mediaServer, String streamKey) {
  252. JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(mediaServer, streamKey);
  253. return jsonObject.getInteger("code") == 0;
  254. }
  255. @Override
  256. public Boolean delStreamProxy(MediaServer mediaServer, String streamKey) {
  257. JSONObject jsonObject = zlmresTfulUtils.delStreamProxy(mediaServer, streamKey);
  258. return jsonObject.getInteger("code") == 0;
  259. }
  260. @Override
  261. public Map<String, String> getFFmpegCMDs(MediaServer mediaServer) {
  262. Map<String, String> result = new HashMap<>();
  263. JSONObject mediaServerConfigResuly = zlmresTfulUtils.getMediaServerConfig(mediaServer);
  264. if (mediaServerConfigResuly != null && mediaServerConfigResuly.getInteger("code") == 0
  265. && mediaServerConfigResuly.getJSONArray("data").size() > 0){
  266. JSONObject mediaServerConfig = mediaServerConfigResuly.getJSONArray("data").getJSONObject(0);
  267. for (String key : mediaServerConfig.keySet()) {
  268. if (key.startsWith("ffmpeg.cmd")){
  269. result.put(key, mediaServerConfig.getString(key));
  270. }
  271. }
  272. }
  273. return result;
  274. }
  275. @Override
  276. public void startSendRtpPassive(MediaServer mediaServer, SendRtpItem sendRtpItem, Integer timeout) {
  277. Map<String, Object> param = new HashMap<>(12);
  278. param.put("vhost","__defaultVhost__");
  279. param.put("app", sendRtpItem.getApp());
  280. param.put("stream", sendRtpItem.getStream());
  281. param.put("ssrc", sendRtpItem.getSsrc());
  282. param.put("src_port", sendRtpItem.getLocalPort());
  283. param.put("pt", sendRtpItem.getPt());
  284. param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  285. param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  286. param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
  287. param.put("recv_stream_id", sendRtpItem.getReceiveStream());
  288. if (timeout != null) {
  289. param.put("close_delay_ms", timeout);
  290. }
  291. if (!sendRtpItem.isTcp()) {
  292. // 开启rtcp保活
  293. param.put("udp_rtcp_timeout", sendRtpItem.isRtcp()? "1":"0");
  294. }
  295. if (!sendRtpItem.isTcpActive()) {
  296. param.put("dst_url",sendRtpItem.getIp());
  297. param.put("dst_port", sendRtpItem.getPort());
  298. }
  299. JSONObject jsonObject = zlmServerFactory.startSendRtpPassive(mediaServer, param, null);
  300. if (jsonObject == null || jsonObject.getInteger("code") != 0 ) {
  301. logger.error("启动监听TCP被动推流失败: {}, 参数:{}", jsonObject.getString("msg"), JSON.toJSONString(param));
  302. throw new ControllerException(jsonObject.getInteger("code"), jsonObject.getString("msg"));
  303. }
  304. logger.info("调用ZLM-TCP被动推流接口, 结果: {}", jsonObject);
  305. logger.info("启动监听TCP被动推流成功[ {}/{} ],{}->{}:{}, " , sendRtpItem.getApp(), sendRtpItem.getStream(),
  306. jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
  307. }
  308. @Override
  309. public void startSendRtpStream(MediaServer mediaServer, SendRtpItem sendRtpItem) {
  310. Map<String, Object> param = new HashMap<>(12);
  311. param.put("vhost", "__defaultVhost__");
  312. param.put("app", sendRtpItem.getApp());
  313. param.put("stream", sendRtpItem.getStream());
  314. param.put("ssrc", sendRtpItem.getSsrc());
  315. param.put("src_port", sendRtpItem.getLocalPort());
  316. param.put("pt", sendRtpItem.getPt());
  317. param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  318. param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  319. param.put("is_udp", sendRtpItem.isTcp() ? "0" : "1");
  320. if (!sendRtpItem.isTcp()) {
  321. // udp模式下开启rtcp保活
  322. param.put("udp_rtcp_timeout", sendRtpItem.isRtcp() ? "1" : "0");
  323. }
  324. param.put("dst_url", sendRtpItem.getIp());
  325. param.put("dst_port", sendRtpItem.getPort());
  326. JSONObject jsonObject = zlmresTfulUtils.startSendRtp(mediaServer, param);
  327. if (jsonObject == null || jsonObject.getInteger("code") != 0 ) {
  328. throw new ControllerException(jsonObject.getInteger("code"), jsonObject.getString("msg"));
  329. }
  330. }
  331. }