package org.mobicents.media.server.ctrl.rtsp; import java.io.File; import java.net.URI; import java.util.concurrent.Callable; import org.apache.log4j.Logger; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.mobicents.media.server.spi.Connection; import org.mobicents.media.server.spi.ConnectionMode; import org.mobicents.media.server.spi.Endpoint; import org.mobicents.media.server.spi.ResourceUnavailableException; import org.mobicents.rtsp.DefaultRtspResponse; import org.mobicents.rtsp.RtspHeaders; import org.mobicents.rtsp.RtspRequest; import org.mobicents.rtsp.RtspResponse; import org.mobicents.rtsp.RtspResponseStatus; import org.mobicents.rtsp.RtspVersion; /** * * @author amit bhayani * */ public class SetupAction implements Callable<RtspResponse> { // TODO : Multicast not taken care // TODO : Only UDP is supported, check that no TCP in Transport private static final Logger logger = Logger.getLogger(SetupAction.class); private final String ENDPOINT_NAME = "/mobicents/media/aap/$"; private static final ConnectionMode mode = ConnectionMode.SEND_ONLY; private final RtspController rtspController; private final RtspRequest request; private final SdpUtils sdpUtils; private final String remoteIp; private String clientPort = null; public SetupAction(RtspController rtspController, RtspRequest request, String remoteIp) { this.rtspController = rtspController; this.request = request; this.sdpUtils = new SdpUtils(); this.remoteIp = remoteIp; } public RtspResponse call() throws Exception { String sessionId = this.request.getHeader(RtspHeaders.Names.SESSION); Session session = null; Endpoint endpoint = null; RtspResponse response = null; if (logger.isDebugEnabled()) { logger.debug("SETUP Request to Play for Session Id = " + sessionId + " Request = " + this.request); } if (sessionId != null) { // Existing session session = this.rtspController.getSession(sessionId); if (session != null) { // Check state to be != PLAYING or RECORDING if (session.getState() == SessionState.PLAYING || session.getState() == SessionState.RECORDING) { // We don't support changing the Transport while state is PLAYING or RECORDING response = new DefaultRtspResponse(RtspVersion.RTSP_1_0, RtspResponseStatus.METHOD_NOT_VALID); response.setHeader(HttpHeaders.Names.SERVER, RtspController.SERVER); response.setHeader(RtspHeaders.Names.CSEQ, this.request.getHeader(RtspHeaders.Names.CSEQ)); return response; } else { // TODO : What here? } } else { response = new DefaultRtspResponse(RtspVersion.RTSP_1_0, RtspResponseStatus.SESSION_NOT_FOUND); response.setHeader(HttpHeaders.Names.SERVER, RtspController.SERVER); response.setHeader(RtspHeaders.Names.CSEQ, this.request.getHeader(RtspHeaders.Names.CSEQ)); return response; } } else { // new session session = new Session(this.rtspController); try { endpoint = rtspController.getNamingService().lookup(ENDPOINT_NAME, false); } catch (ResourceUnavailableException e) { logger.warn("There is no free endpoint: " + ENDPOINT_NAME); response = new DefaultRtspResponse(RtspVersion.RTSP_1_0, RtspResponseStatus.SERVICE_UNAVAILABLE); response.setHeader(HttpHeaders.Names.SERVER, RtspController.SERVER); response.setHeader(RtspHeaders.Names.CSEQ, this.request.getHeader(RtspHeaders.Names.CSEQ)); return response; } Connection connection = null; try { connection = endpoint.createConnection(mode); if (logger.isDebugEnabled()) { logger.debug("SessionId=" + session.getId() + ", Endpoint: " + endpoint.getLocalName() + ", Created connection "); } } catch (Exception e) { logger.error(e); response = new DefaultRtspResponse(RtspVersion.RTSP_1_0, RtspResponseStatus.SERVICE_UNAVAILABLE); response.setHeader(HttpHeaders.Names.SERVER, RtspController.SERVER); response.setHeader(RtspHeaders.Names.CSEQ, this.request.getHeader(RtspHeaders.Names.CSEQ)); return response; } int port = -1; String transport = this.request.getHeader(RtspHeaders.Names.TRANSPORT); String[] transParameters = transport.split(";"); for (String s : transParameters) { if (s.contains("client_port")) { this.clientPort = s; String[] values = s.split("="); values = values[1].split("-"); port = Integer.parseInt(values[0]); break; } } String mediaDir = this.rtspController.getMediaDir(); String sdp = null; URI objUri = new URI(this.request.getUri()); mediaDir += objUri.getPath(); if (logger.isDebugEnabled()) { logger.debug("Final path = " + mediaDir); } File f = new File(mediaDir); if (f.isFile() && f.exists()) { sdp = this.sdpUtils.getSdp(f, this.remoteIp, port, this.request.getUri()); } else { response = new DefaultRtspResponse(RtspVersion.RTSP_1_0, RtspResponseStatus.NOT_FOUND); response.setHeader(HttpHeaders.Names.SERVER, RtspController.SERVER); response.setHeader(RtspHeaders.Names.CSEQ, this.request.getHeader(RtspHeaders.Names.CSEQ)); return response; } try { connection.setRemoteDescriptor(sdp); } catch (Exception e) { logger.error(e); response = new DefaultRtspResponse(RtspVersion.RTSP_1_0, RtspResponseStatus.SERVICE_UNAVAILABLE); response.setHeader(HttpHeaders.Names.SERVER, RtspController.SERVER); response.setHeader(RtspHeaders.Names.CSEQ, this.request.getHeader(RtspHeaders.Names.CSEQ)); return response; } String localDesc = connection.getLocalDescriptor(); int serverPort = sdpUtils.getAudioPort(localDesc); transport = "RTP/AVP/UDP;unicast;" + this.clientPort + ";server_port=" + serverPort + "-" + serverPort; response = new DefaultRtspResponse(RtspVersion.RTSP_1_0, RtspResponseStatus.OK); response.setHeader(HttpHeaders.Names.SERVER, RtspController.SERVER); response.setHeader(RtspHeaders.Names.CSEQ, this.request.getHeader(RtspHeaders.Names.CSEQ)); response.setHeader(RtspHeaders.Names.SESSION, session.getId()); response.setHeader(RtspHeaders.Names.TRANSPORT, transport); session.setState(SessionState.READY); ConnectionActivity connectionActivity = session.addConnection(connection); if (logger.isDebugEnabled()) { logger.debug("Created connection activity=" + connectionActivity.getID() + ", origin connection ID =" + connection.getId()); } this.rtspController.addSession(session); if (logger.isDebugEnabled()) { logger.debug("Save reference to the callID=" + session.getId()); } } return response; } }