package org.mconf.bbb; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.mconf.bbb.BigBlueButtonClient.OnExceptionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.flazr.rtmp.client.ClientHandler; import com.flazr.rtmp.client.ClientOptions; public abstract class RtmpConnection extends ClientHandler implements ChannelFutureListener { private static final Logger log = LoggerFactory.getLogger(RtmpConnection.class); final protected BigBlueButtonClient context; public RtmpConnection(ClientOptions options, BigBlueButtonClient context) { super(options); this.context = context; } private ClientBootstrap bootstrap = null; private ChannelFuture future = null; private ChannelFactory factory = null; public boolean connect() { if (factory == null) factory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); bootstrap = new ClientBootstrap(factory); bootstrap.setPipelineFactory(pipelineFactory()); future = bootstrap.connect(new InetSocketAddress(options.getHost(), options.getPort())); future.addListener(this); return true; } public void disconnect() { if (future != null) { if (future.getChannel().isConnected()) { log.debug("Channel is connected, disconnecting"); //future.getChannel().close(); //ClosedChannelException future.getChannel().disconnect(); future.getChannel().getCloseFuture().awaitUninterruptibly(); } future.removeListener(this); factory.releaseExternalResources(); future = null; factory = null; bootstrap = null; } } abstract protected ChannelPipelineFactory pipelineFactory(); @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) onConnectedSuccessfully(); else onConnectedUnsuccessfully(); } protected void onConnectedUnsuccessfully() { } protected void onConnectedSuccessfully() { } public BigBlueButtonClient getContext() { return context; } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { String exceptionMessage = e.getCause().getMessage(); if (exceptionMessage != null && exceptionMessage.contains("ArrayIndexOutOfBoundsException") && exceptionMessage.contains("bad value / byte: 101 (hex: 65)")) { log.debug("Ignoring malformed metadata"); return; } else { super.exceptionCaught(ctx, e); for (OnExceptionListener listener : context.getExceptionListeners()) listener.onException(e.getCause()); } } }