package com.genersoft.iot.vmp.gb28181.transmit.request.impl; import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; import javax.sip.SipException; import javax.sip.address.SipURI; import javax.sip.header.ContentTypeHeader; import javax.sip.header.FromHeader; import javax.sip.header.SubjectHeader; import javax.sip.message.Request; import javax.sip.message.Response; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.sdp.Codec; import com.genersoft.iot.vmp.gb28181.sdp.MediaDescription; import com.genersoft.iot.vmp.gb28181.sdp.SdpParser; import com.genersoft.iot.vmp.gb28181.sdp.SessionDescription; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult; import com.genersoft.iot.vmp.vmanager.service.IPlayService; import gov.nist.javax.sip.address.AddressImpl; import gov.nist.javax.sip.address.SipUri; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import java.io.IOException; import java.text.ParseException; import java.util.List; /** * @Description:处理INVITE请求 * @author: panll * @date: 2021年1月14日 */ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); private SIPCommanderFroPlatform cmderFroPlatform; private IVideoManagerStorager storager; private SIPCommander cmder; private IPlayService playService; /** * 处理invite请求 * * @param evt * 请求消息 */ @Override public void process(RequestEvent evt) { // Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令 try { Request request = evt.getRequest(); SipURI sipURI = (SipURI) request.getRequestURI(); String channelId = sipURI.getUser(); String platformId = null; // SubjectHeader subjectHeader = (SubjectHeader)request.getHeader(SubjectHeader.NAME); // // 查询通道是否存在 不存在回复404 // if (subjectHeader != null) { // 存在则从subjectHeader 获取平台信息 // String subject = subjectHeader.getSubject(); // if (subject != null) { // String[] info1 = subject.split(","); // if (info1 != null && info1 .length == 2) { // String[] info2 = info1[1].split(":"); // if (info2 != null && info2.length == 2) { // platformId = info2[0]; // } // } // } // } FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); AddressImpl address = (AddressImpl) fromHeader.getAddress(); SipUri uri = (SipUri) address.getURI(); platformId = uri.getUser(); if (platformId == null || channelId == null) { response400Ack(evt); // 参数不全, 发400,请求错误 return; } // 查询平台下是否有该通道 DeviceChannel channel = storager.queryChannelInParentPlatform(platformId, channelId); if (channel == null) { response404Ack(evt); // 通道不存在,发404,资源不存在 return; }else { response100Ack(evt); // 通道存在,发100,trying } // 解析sdp消息 SessionDescription sdp = new SdpParser().parse(request.getRawContent()); // 获取支持的格式 List mediaDescriptions = sdp.getMediaDescriptions(); // 查看是否支持PS 负载96 String ip = null; int port = -1; for (MediaDescription mediaDescription : mediaDescriptions) { List codecs = mediaDescription.getCodecs(); for (Codec codec : codecs) { if("96".equals(codec.getPayloadType()) || "PS".equals(codec.getName()) || "ps".equals(codec.getName())) { ip = mediaDescription.getIpAddress().getHostName(); port = mediaDescription.getPort(); break; } } } if (ip == null || port == -1) { // TODO 没有合适的视频流格式, 可配置是否使用第一个media信息 if (mediaDescriptions.size() > 0) { ip = mediaDescriptions.get(0).getIpAddress().getHostName(); port = mediaDescriptions.get(0).getPort(); } } if (ip == null || port == -1) { response488Ack(evt); return; } String ssrc = sdp.getSsrc(); Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); if (device == null) { logger.warn("点播平台{}的通道{}时未找到设备信息", platformId, channel); response500Ack(evt); return; } // 通知下级推流, PlayResult playResult = playService.play(device.getDeviceId(), channelId, (response)->{ // 收到推流, 回复200OK },(event -> { // 未知错误。直接转发设备点播的错误 Response response = null; try { response = getMessageFactory().createResponse(event.getResponse().getStatusCode(), evt.getRequest()); getServerTransaction(evt).sendResponse(response); } catch (ParseException | SipException | InvalidArgumentException e) { e.printStackTrace(); } })); playResult.getResult(); // 查找合适的端口推流, // 发送 200ok // 收到ack后调用推流接口 } catch (SipException | InvalidArgumentException | ParseException e) { e.printStackTrace(); } catch (IOException e) { logger.warn("sdp解析错误"); e.printStackTrace(); } } /*** * 回复100 trying * @param evt * @throws SipException * @throws InvalidArgumentException * @throws ParseException */ private void response100Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { Response response = getMessageFactory().createResponse(Response.TRYING, evt.getRequest()); getServerTransaction(evt).sendResponse(response); } /*** * 回复200 OK * @param evt * @throws SipException * @throws InvalidArgumentException * @throws ParseException */ private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException { Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); ContentTypeHeader contentTypeHeader = getHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); response.setContent(sdp, contentTypeHeader); getServerTransaction(evt).sendResponse(response); } /*** * 回复400 * @param evt * @throws SipException * @throws InvalidArgumentException * @throws ParseException */ private void response400Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { Response response = getMessageFactory().createResponse(Response.BAD_REQUEST, evt.getRequest()); getServerTransaction(evt).sendResponse(response); } /*** * 回复404 * @param evt * @throws SipException * @throws InvalidArgumentException * @throws ParseException */ private void response404Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest()); getServerTransaction(evt).sendResponse(response); } /*** * 回复488 * @param evt * @throws SipException * @throws InvalidArgumentException * @throws ParseException */ private void response488Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { Response response = getMessageFactory().createResponse(Response.NOT_ACCEPTABLE_HERE, evt.getRequest()); getServerTransaction(evt).sendResponse(response); } /*** * 回复500 * @param evt * @throws SipException * @throws InvalidArgumentException * @throws ParseException */ private void response500Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { Response response = getMessageFactory().createResponse(Response.SERVER_INTERNAL_ERROR, evt.getRequest()); getServerTransaction(evt).sendResponse(response); } public SIPCommanderFroPlatform getCmderFroPlatform() { return cmderFroPlatform; } public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) { this.cmderFroPlatform = cmderFroPlatform; } public IVideoManagerStorager getStorager() { return storager; } public void setStorager(IVideoManagerStorager storager) { this.storager = storager; } public SIPCommander getCmder() { return cmder; } public void setCmder(SIPCommander cmder) { this.cmder = cmder; } public IPlayService getPlayService() { return playService; } public void setPlayService(IPlayService playService) { this.playService = playService; } }