package com.ard.zlm.service.impl; import com.ard.zlm.api.domain.RTPServerParam; import com.ard.zlm.common.InviteErrorCode; import com.ard.zlm.config.DynamicTask; import com.ard.zlm.config.UserSetting; import com.ard.zlm.domain.OpenRTPServerResult; import com.ard.zlm.domain.SSRCInfo; import com.ard.zlm.hook.Hook; import com.ard.zlm.hook.HookSubscribe; import com.ard.zlm.hook.HookType; import com.ard.zlm.service.ErrorCallback; import com.ard.zlm.service.IMediaServerService; import com.ard.zlm.service.IReceiveRtpServerService; import com.ard.zlm.session.SSRCFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import java.util.UUID; /** * @FileName RtpServerServiceImpl * @Description * @Author fengcheng * @date 2026-04-07 **/ @Slf4j @Service public class RtpServerServiceImpl implements IReceiveRtpServerService { @Autowired private SSRCFactory ssrcFactory; @Autowired private DynamicTask dynamicTask; @Autowired private HookSubscribe subscribe; @Autowired private UserSetting userSetting; @Autowired @Lazy private IMediaServerService mediaServerService; @Override public SSRCInfo openRTPServer(RTPServerParam rtpServerParam, ErrorCallback callback) { if (callback == null) { log.warn("[开启RTP收流] 失败,回调为NULL"); return null; } if (rtpServerParam.getMediaServer() == null) { log.warn("[开启RTP收流] 失败,媒体节点为NULL"); return null; } if (rtpServerParam.isSsrcCheck() && rtpServerParam.getTcpMode() > 0) { // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 log.warn("[openRTPServer] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验"); } int rtpServerPort = mediaServerService.createRTPServer( rtpServerParam.getMediaServer(), rtpServerParam.getApp(), rtpServerParam.getStreamId(), rtpServerParam.isSsrcCheck() ? Long.parseLong(rtpServerParam.getSsrc()) : 0, rtpServerParam.getPort(), rtpServerParam.isOnlyAuto(), rtpServerParam.isDisableAudio(), rtpServerParam.isReUsePort(), rtpServerParam.getTcpMode()); if (rtpServerPort == 0) { callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "开启RTPServer失败", null); // 释放ssrc if (rtpServerParam.getPresetSsrc() == null) { ssrcFactory.releaseSsrc(rtpServerParam.getMediaServer().getId(), rtpServerParam.getSsrc()); } return null; } rtpServerParam.setPort(rtpServerPort); // 设置流超时的定时任务 String timeOutTaskKey = UUID.randomUUID().toString(); SSRCInfo ssrcInfo = new SSRCInfo(rtpServerPort, rtpServerParam.getSsrc(), rtpServerParam.getApp(), rtpServerParam.getStreamId(), timeOutTaskKey); OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult(); openRTPServerResult.setSsrcInfo(ssrcInfo); Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, ssrcInfo.getApp(), rtpServerParam.getStreamId(), rtpServerParam.getMediaServer().getId()); dynamicTask.startDelay(timeOutTaskKey, () -> { // 收流超时 // 释放ssrc if (rtpServerParam.getPresetSsrc() == null) { ssrcFactory.releaseSsrc(rtpServerParam.getMediaServer().getId(), rtpServerParam.getSsrc()); } // 关闭收流端口 mediaServerService.closeRTPServer(rtpServerParam.getMediaServer(), rtpServerParam.getStreamId()); subscribe.removeSubscribe(rtpHook); callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), openRTPServerResult); }, userSetting.getPlayTimeout()); // 开启流到来的监听 subscribe.addSubscribe(rtpHook, (hookData) -> { dynamicTask.stop(timeOutTaskKey); // hook响应 openRTPServerResult.setHookData(hookData); callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), openRTPServerResult); subscribe.removeSubscribe(rtpHook); }); return ssrcInfo; } }