/** * */ package video.serverProxy; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.charset.Charset; import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.transport.socket.nio.NioSocketConnector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import video.lib.Configuration; import video.lib.Constants; import video.lib.RtspCodecFactory; import video.lib.RtspMessage; import video.lib.RtspResponse; import video.lib.RtspStatusCode; import video.lib.ServiceInterface; import video.transport.TransportService; /** * @author yuezhu * */ public class RtspServerService implements ServiceInterface { private static final Logger LOGGER = LoggerFactory.getLogger(RtspServerService.class); private static TransportService service; private static Thread rtspDispatcherThread; private static boolean running = false; public RtspServerService(TransportService transportService) { service = transportService; } /** * Setup a RTSP connection with the streaming server * @param hostname * @param port * @return */ private static IoSession connectToServer(String hostname, int port) { NioSocketConnector connector = new NioSocketConnector(); connector.setConnectTimeoutMillis(Constants.CONNECT_TIMEOUT); connector.setHandler(new MinaServerHandler()); connector.getFilterChain().addLast(RtspCodecFactory.TOKEN.toString(), new ProtocolCodecFilter(new RtspCodecFactory(Charset.forName(Constants.CHARSET)))); LOGGER.info("About to connect " + hostname + ":" + port); ConnectFuture connFuture = connector.connect(new InetSocketAddress(hostname, port)); connFuture.awaitUninterruptibly(); if (connFuture.isConnected()) { LOGGER.info("Connected to " + hostname + ":" + port); return connFuture.getSession(); } else { return null; } } /* (non-Javadoc) * @see demo.video.common.ServiceInterface#start() */ @Override public void start() throws IOException { running = true; rtspDispatcherThread = new Thread() { @Override public void run() { while (running) { rtspMessageDispatcher(); } } }; rtspDispatcherThread.start(); LOGGER.debug("Rtsp server service started."); } /* (non-Javadoc) * @see demo.video.common.ServiceInterface#stop() */ @Override public void stop() throws IOException { running = false; } /** * Receive RTSP messages from the client side proxy. * @return * @throws IOException */ private static byte[] recvMessageBytesFromRemote() throws IOException { return service.getRTSPTransportChannel().recv(); } /** * Dispatcher RTSP messages received from the client side proxy. */ private static void rtspMessageDispatcher() { byte[] bytes = null; try { bytes = recvMessageBytesFromRemote(); } catch (IOException e) { LOGGER.error("Failed to recv RTSP message via transport service: " + e.toString()); return; } // Get client session ID long clientSessionId = RtspServerHandler.getClientSessionId(bytes); // Get the message bytes byte[] messageBytes = RtspServerHandler.getMessageBytes(bytes); LOGGER.debug("Message received for client session ID=" + clientSessionId); // Construct a RTSP message from bytes received from the client side proxy. RtspMessage message = RtspMessage.parse(messageBytes); //message.setProxy(); RtspServerHandler rtspServerHandler = null; String rtspSessionId = message.getField("Session"); if (rtspSessionId != null) { LOGGER.debug("Get RtspServerHandler by RTSP session ID"); rtspServerHandler = RtspServerHandler.getByRtspSessionId(rtspSessionId); if (rtspServerHandler == null) { rtspServerHandler = RtspServerHandler.getByClientSessionId(clientSessionId); RtspServerHandler.putRtspSessionId(rtspSessionId, rtspServerHandler); } } else { rtspServerHandler = RtspServerHandler.getByClientSessionId(clientSessionId); } if (rtspServerHandler == null) { // This is a new client, allocate a new handler for it. LOGGER.info("A message from New client (id=" + clientSessionId + ")"); int port = Configuration.getInt("streaming.server.port", Constants.STREAMING_SERVER_PORT); String hostname = Configuration.getString("streaming.server.hostname", Constants.STREAMING_SERVER_HOSTNAME); IoSession session = connectToServer(hostname, port); rtspServerHandler = new RtspServerHandler(session, service, clientSessionId); if (session != null) { // Save the handler to its session session.setAttribute(RtspServerHandler.TOKEN, rtspServerHandler); } else { // The streaming server is unreachable LOGGER.info("Streaming server " + hostname + ":" + port + " is not reachable."); rtspServerHandler.sendRtspMessageToRemote(RtspResponse.newInstance(RtspStatusCode.DestinationUnreachable, message.getField("CSeq"))); rtspServerHandler.close(); return; } } // Pass the message received from the client side proxy to the corresponding handler rtspServerHandler.onMessageReceivedFromRemote(message); } }