/* * RED5 Open Source Flash Server - https://github.com/Red5/ Copyright 2006-2015 by respective authors (see below). All rights reserved. Licensed under the Apache License, Version * 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless * required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.red5.client.net.rtmp; import java.net.InetSocketAddress; import java.util.Map; import java.util.concurrent.TimeUnit; import org.apache.mina.core.future.CloseFuture; import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.future.IoFutureListener; import org.apache.mina.core.session.IoSession; import org.apache.mina.transport.socket.SocketConnector; import org.apache.mina.transport.socket.nio.NioSocketConnector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * RTMP client implementation supporting "rtmp" and "rtmpe" protocols. * * @author The Red5 Project * @author Christian Eckerle ([email protected]) * @author Joachim Bauch ([email protected]) * @author Paul Gregoire ([email protected]) * @author Steven Gong ([email protected]) * @author Anton Lebedevich ([email protected]) * @author Tiago Daniel Jacobs ([email protected]) * @author Jon Valliere */ public class RTMPClient extends BaseRTMPClientHandler { private static final Logger log = LoggerFactory.getLogger(RTMPClient.class); protected static final int CONNECTOR_WORKER_TIMEOUT = 7000; // seconds // I/O handler private final RTMPMinaIoHandler ioHandler; // Socket connector, disposed on disconnect protected SocketConnector socketConnector; // ConnectFuture protected ConnectFuture future; // Connected IoSession private IoSession session; /** Constructs a new RTMPClient. */ public RTMPClient() { ioHandler = new RTMPMinaIoHandler(); ioHandler.setHandler(this); } /** {@inheritDoc} */ @Override public Map<String, Object> makeDefaultConnectionParams(String server, int port, String application) { Map<String, Object> params = super.makeDefaultConnectionParams(server, port, application); if (!params.containsKey("tcUrl")) { params.put("tcUrl", String.format("%s://%s:%s/%s", protocol, server, port, application)); } return params; } /** {@inheritDoc} */ @Override protected void startConnector(String server, int port) { socketConnector = new NioSocketConnector(); socketConnector.setHandler(ioHandler); future = socketConnector.connect(new InetSocketAddress(server, port)); future.addListener(new IoFutureListener<ConnectFuture>() { @Override public void operationComplete(ConnectFuture future) { try { // will throw RuntimeException after connection error session = future.getSession(); } catch (Throwable e) { socketConnector.dispose(false); // if there isn't an ClientExceptionHandler set, a RuntimeException may be thrown in handleException handleException(e); } } }); // Now wait for the connect to be completed future.awaitUninterruptibly(CONNECTOR_WORKER_TIMEOUT); } /** {@inheritDoc} */ @Override public void disconnect() { if (future != null) { try { // session will be null if connect failed if (session != null) { // close, now CloseFuture closeFuture = session.closeNow(); // now wait for the close to be completed if (closeFuture.await(1000, TimeUnit.MILLISECONDS)) { if (!future.isCanceled()) { if (future.cancel()) { log.debug("Connect future cancelled after close future"); } } } } else if (future.cancel()) { log.debug("Connect future cancelled"); } } catch (Exception e) { log.warn("Exception during disconnect", e); } finally { // we can now dispose the connector socketConnector.dispose(false); } } super.disconnect(); } /** * Sets the RTMP protocol, the default is "rtmp". If "rtmps" or "rtmpt" are required, the appropriate client type should be selected. * * @param protocol * the protocol to set * @throws Exception thrown */ @Override public void setProtocol(String protocol) throws Exception { this.protocol = protocol; if ("rtmps".equals(protocol) || "rtmpt".equals(protocol) || "rtmpte".equals(protocol) || "rtmfp".equals(protocol)) { throw new Exception("Unsupported protocol specified, please use the correct client for the intended protocol."); } } }