All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.red5.server.net.rtmp.RTMPMinaTransport Maven / Gradle / Ivy

Go to download

Ant Media Server supports RTMP, RTSP, MP4, HLS, WebRTC, Adaptive Streaming, etc.

There is a newer version: 2.10.0
Show newest version
/*
 * RED5 Open Source Media Server - https://github.com/Red5/
 * 
 * Copyright 2006-2016 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.server.net.rtmp;

import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.StandardMBean;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.buffer.SimpleBufferAllocator;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.service.AbstractIoService;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.service.IoServiceStatistics;
import org.apache.mina.core.service.SimpleIoProcessorPool;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioProcessor;
import org.apache.mina.transport.socket.nio.NioSession;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.red5.server.jmx.mxbeans.RTMPMinaTransportMXBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Transport setup class configures socket acceptor and thread pools for RTMP in Mina.
 * 
 * 
* Note: This code originates from AsyncWeb. Originally modified by Luke Hubbard.
* * @author Luke Hubbard * @author Paul Gregoire */ public class RTMPMinaTransport implements RTMPMinaTransportMXBean { private static final Logger log = LoggerFactory.getLogger(RTMPMinaTransport.class); // utilized when enableDefaultAcceptor is false private ThreadPoolExecutor executor; protected SocketAcceptor acceptor; protected Set addresses = new HashSet(); protected IoHandlerAdapter ioHandler; protected int ioThreads = Runtime.getRuntime().availableProcessors() * 2; /** * MBean object name used for de/registration purposes. */ protected ObjectName serviceManagerObjectName; protected IoServiceStatistics stats; protected boolean enableMinaLogFilter; protected boolean enableMinaMonitor; protected int minaPollInterval = 1000; protected boolean tcpNoDelay = true; protected boolean useHeapBuffers = true; protected int sendBufferSize = 65536; protected int receiveBufferSize = 65536; private int readerIdleTime = 2; private int trafficClass = 0x08 | 0x10; private int backlog = 32; private int thoughputCalcInterval = 1; private long executorKeepAliveTime = 60000; // use the default mina acceptor and associated options private boolean enableDefaultAcceptor = true; private int initialPoolSize = 0; private int maxPoolSize = Runtime.getRuntime().availableProcessors() + 1; private int maxProcessorPoolSize = 16; private boolean keepAlive; private void initIOHandler() { if (ioHandler == null) { log.info("No RTMP IO Handler associated - using defaults"); ioHandler = new RTMPMinaIoHandler(); } } public void start() throws Exception { initIOHandler(); IoBuffer.setUseDirectBuffer(!useHeapBuffers); // this is global, oh well if (useHeapBuffers) { // dont pool for heap buffers IoBuffer.setAllocator(new SimpleBufferAllocator()); } log.info("RTMP Mina Transport Settings\nAcceptor style: {} I/O threads: {}\nTCP no-delay: {} keep-alive: {}", new Object[] { (enableDefaultAcceptor ? "default" : "blocking-queue"), ioThreads, tcpNoDelay, keepAlive }); // use the defaults if (enableDefaultAcceptor) { //constructs an acceptor using default parameters, and given number of NioProcessor for multithreading I/O operations. acceptor = new NioSocketAcceptor(ioThreads); } else { // simple pool for i/o processors SimpleIoProcessorPool pool = new SimpleIoProcessorPool(NioProcessor.class, maxProcessorPoolSize); // executor for acceptors, defaults to 32k for work queue executor = new ThreadPoolExecutor(initialPoolSize, maxPoolSize, executorKeepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(Short.MAX_VALUE)); // our adjusted socket acceptor with tweaked executor and pool acceptor = new NioSocketAcceptor(executor, pool); } // use only for low level debugging if (enableMinaLogFilter) { DefaultIoFilterChainBuilder chain = acceptor.getFilterChain(); LoggingFilter logFilter = new LoggingFilter(RTMPMinaTransport.class); //logFilter.setExceptionCaughtLogLevel(LogLevel.TRACE); //logFilter.setMessageReceivedLogLevel(LogLevel.TRACE); //logFilter.setMessageSentLogLevel(LogLevel.TRACE); //logFilter.setSessionClosedLogLevel(LogLevel.TRACE); //logFilter.setSessionCreatedLogLevel(LogLevel.TRACE); //logFilter.setSessionIdleLogLevel(LogLevel.TRACE); //logFilter.setSessionOpenedLogLevel(LogLevel.TRACE); chain.addLast("logger", logFilter); } // close sessions when the acceptor is stopped acceptor.setCloseOnDeactivation(true); // set acceptor props acceptor.setHandler(ioHandler); // requested maximum length of the queue of incoming connections acceptor.setBacklog(backlog); // get the current session config that would be used during create SocketSessionConfig sessionConf = acceptor.getSessionConfig(); // reuse the addresses sessionConf.setReuseAddress(true); sessionConf.setTcpNoDelay(tcpNoDelay); sessionConf.setSendBufferSize(sendBufferSize); // sessionConf.setReceiveBufferSize(receiveBufferSize); sessionConf.setMaxReadBufferSize(receiveBufferSize); // sets the interval (seconds) between each throughput calculation, the default value is 3 seconds sessionConf.setThroughputCalculationInterval(thoughputCalcInterval); // set the reader idle time (seconds) sessionConf.setReaderIdleTime(readerIdleTime); sessionConf.setKeepAlive(keepAlive); // to prevent setting of the traffic class we expect a value of -1 if (trafficClass == -1) { log.info("Traffic class modification is disabled"); } else { // set the traffic class - http://docs.oracle.com/javase/6/docs/api/java/net/Socket.html#setTrafficClass(int) // IPTOS_LOWCOST (0x02) // IPTOS_RELIABILITY (0x04) // IPTOS_THROUGHPUT (0x08) * // IPTOS_LOWDELAY (0x10) * sessionConf.setTrafficClass(trafficClass); } // get info log.info("Send buffer size: {} recv buffer size: {} so linger: {} traffic class: {}", new Object[] { sessionConf.getSendBufferSize(), sessionConf.getReceiveBufferSize(), sessionConf.getSoLinger(), sessionConf.getTrafficClass() }); // set reuse address on the socket acceptor as well acceptor.setReuseAddress(true); try { // loop through the addresses and bind Set socketAddresses = new HashSet(); for (String addr : addresses) { if (addr.indexOf(':') != -1) { String[] parts = addr.split(":"); socketAddresses.add(new InetSocketAddress(parts[0], Integer.valueOf(parts[1]))); } else { socketAddresses.add(new InetSocketAddress(addr, 1935)); } } log.debug("Binding to {}", socketAddresses.toString()); acceptor.bind(socketAddresses); // create a new mbean for this instance RTMPMinaTransport String cName = this.getClass().getName(); if (cName.indexOf('.') != -1) { cName = cName.substring(cName.lastIndexOf('.')).replaceFirst("[\\.]", ""); } //enable only if user wants it if (enableMinaMonitor) { //add a stats to allow for more introspection into the workings of mina stats = new IoServiceStatistics((AbstractIoService) acceptor); //poll every second stats.setThroughputCalculationInterval(minaPollInterval); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { serviceManagerObjectName = new ObjectName("org.red5.server:type=RTMPMinaTransport"); mbs.registerMBean(new StandardMBean(this, RTMPMinaTransportMXBean.class, true), serviceManagerObjectName); } catch (Exception e) { log.warn("Error on jmx registration", e); } } } catch (Exception e) { log.error("Exception occurred during resolve / bind", e); } } public void stop() { log.info("RTMP Mina Transport stop"); // first we unbind to prevent new connections acceptor.unbind(); // second we shutdown the customized executor, if we used it if (!enableDefaultAcceptor) { executor.shutdownNow(); } // lastly dispose the acceptor without allowing for deadlocks acceptor.dispose(false); // deregister with jmx if (serviceManagerObjectName != null) { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); try { mbs.unregisterMBean(serviceManagerObjectName); } catch (Exception e) { log.warn("Error on jmx unregistration", e); } } } public void setAddress(String address) { addresses.add(address); log.info("RTMP will be bound to {}", address); } public void setAddresses(List addrs) { for (String addr : addrs) { addresses.add(addr); } log.info("RTMP will be bound to {}", addresses); } public void setIoHandler(IoHandlerAdapter rtmpIOHandler) { this.ioHandler = rtmpIOHandler; } public void setIoThreads(int ioThreads) { this.ioThreads = ioThreads; } /** * @param sendBufferSize * the sendBufferSize to set */ public void setSendBufferSize(int sendBufferSize) { this.sendBufferSize = sendBufferSize; } /** * @param receiveBufferSize * the receiveBufferSize to set */ public void setReceiveBufferSize(int receiveBufferSize) { this.receiveBufferSize = receiveBufferSize; } /** * @param trafficClass * the trafficClass to set */ public void setTrafficClass(int trafficClass) { this.trafficClass = trafficClass; } /** * @param backlog * the backlog to set */ public void setBacklog(int backlog) { this.backlog = backlog; } /** * @param thoughputCalcInterval * the thoughputCalcInterval to set */ public void setThoughputCalcInterval(int thoughputCalcInterval) { this.thoughputCalcInterval = thoughputCalcInterval; } /** * @param executorKeepAliveTime * the executorKeepAliveTime to set */ public void setExecutorKeepAliveTime(long executorKeepAliveTime) { this.executorKeepAliveTime = executorKeepAliveTime; } public void setEnableDefaultAcceptor(boolean enableDefaultAcceptor) { this.enableDefaultAcceptor = enableDefaultAcceptor; } public void setInitialPoolSize(int initialPoolSize) { this.initialPoolSize = initialPoolSize; } public void setMaxPoolSize(int maxPoolSize) { this.maxPoolSize = maxPoolSize; } /** * @param maxProcessorPoolSize * the maxProcessorPoolSize to set */ public void setMaxProcessorPoolSize(int maxProcessorPoolSize) { this.maxProcessorPoolSize = maxProcessorPoolSize; } public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } /** * @param keepAlive * the keepAlive to set */ public void setKeepAlive(boolean keepAlive) { this.keepAlive = keepAlive; } public void setUseHeapBuffers(boolean useHeapBuffers) { this.useHeapBuffers = useHeapBuffers; } /** * @return the enableMinaLogFilter */ public boolean isEnableMinaLogFilter() { return enableMinaLogFilter; } /** * @param enableMinaLogFilter * the enableMinaLogFilter to set */ public void setEnableMinaLogFilter(boolean enableMinaLogFilter) { this.enableMinaLogFilter = enableMinaLogFilter; } /** * @param enableMinaMonitor * the enableMinaMonitor to set */ public void setEnableMinaMonitor(boolean enableMinaMonitor) { this.enableMinaMonitor = enableMinaMonitor; } public void setMinaPollInterval(int minaPollInterval) { this.minaPollInterval = minaPollInterval; } /** * @param readerIdleTime * the readerIdleTime to set */ public void setReaderIdleTime(int readerIdleTime) { this.readerIdleTime = readerIdleTime; } /** * Returns all the bound addresses and ports as string. * * @return addresses */ public String getAddress() { return addresses.toString(); } /** * Returns the current statistics as a json formatted string. * * @return json */ public String getStatistics() { StringBuilder json = new StringBuilder("[Statistics{"); if (stats != null) { // returns the cumulative number of sessions which were managed (or are being managed) by this service, which means 'currently managed session count + closed session count' json.append("cumulativeManagedSessionCount="); json.append(stats.getCumulativeManagedSessionCount()); json.append(','); // returns the maximum number of sessions which were being managed at the same time json.append("largestManagedSessionCount="); json.append(stats.getLargestManagedSessionCount()); json.append(','); // returns the maximum of the readBytesThroughput json.append("largestReadBytesThroughput="); json.append(stats.getLargestReadBytesThroughput()); json.append(','); // returns the maximum of the readMessagesThroughput json.append("largestReadMessagesThroughput="); json.append(stats.getLargestReadMessagesThroughput()); json.append(','); // returns the maximum of the writtenBytesThroughput json.append("largestWrittenBytesThroughput="); json.append(stats.getLargestWrittenBytesThroughput()); json.append(','); // returns the maximum of the writtenMessagesThroughput json.append("largestWrittenMessagesThroughput="); json.append(stats.getLargestWrittenMessagesThroughput()); json.append(','); // returns the time in millis when I/O occurred lastly json.append("lastIoTime="); json.append(stats.getLastIoTime()); json.append(','); // returns the time in millis when read operation occurred lastly json.append("lastReadTime="); json.append(stats.getLastReadTime()); json.append(','); // returns the time in millis when write operation occurred lastly json.append("lastWriteTime="); json.append(stats.getLastWriteTime()); json.append(','); // returns the number of bytes read by this service json.append("readBytes="); json.append(stats.getReadBytes()); json.append(','); // returns the number of read bytes per second json.append("readBytesThroughput="); json.append(stats.getReadBytesThroughput()); json.append(','); // returns the number of messages this services has read json.append("readMessages="); json.append(stats.getReadMessages()); json.append(','); // returns the number of read messages per second json.append("readMessagesThroughput="); json.append(stats.getReadMessagesThroughput()); json.append(','); // returns the count of bytes scheduled for write json.append("scheduledWriteBytes="); json.append(stats.getScheduledWriteBytes()); json.append(','); // returns the count of messages scheduled for write json.append("scheduledWriteMessages="); json.append(stats.getScheduledWriteMessages()); json.append(','); // returns the interval (seconds) between each throughput calculation json.append("throughputCalculationInterval="); json.append(stats.getThroughputCalculationInterval()); json.append(','); // returns the interval (milliseconds) between each throughput calculation json.append("throughputCalculationIntervalInMillis="); json.append(stats.getThroughputCalculationIntervalInMillis()); json.append(','); // returns the number of bytes written out by this service json.append("writtenBytes="); json.append(stats.getWrittenBytes()); json.append(','); // returns the number of written bytes per second json.append("writtenBytesThroughput="); json.append(stats.getWrittenBytesThroughput()); json.append(','); // returns the number of messages this service has written json.append("writtenMessages="); json.append(stats.getWrittenMessages()); json.append(','); // returns the number of written messages per second json.append("writtenMessagesThroughput="); json.append(stats.getWrittenMessagesThroughput()); json.append("}]"); } return json.toString(); } public String toString() { return String.format("RTMP Mina Transport %s", addresses.toString()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy