
org.jitsi.service.neomedia.DefaultStreamConnector Maven / Gradle / Ivy
Show all versions of libjitsi Show documentation
/*
* Copyright @ 2015 Atlassian Pty Ltd
*
* 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.jitsi.service.neomedia;
import java.net.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.libjitsi.*;
import org.jitsi.utils.logging.*;
/**
* Represents a default implementation of StreamConnector which is
* initialized with a specific pair of control and data DatagramSockets
* and which closes them (if they exist) when its {@link #close()} is invoked.
*
* @author Lubomir Marinov
*/
public class DefaultStreamConnector
implements StreamConnector
{
/**
* The Logger used by the DefaultStreamConnector class and
* its instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(DefaultStreamConnector.class);
/**
* The default number of binds that a Media Service Implementation should
* execute in case a port is already bound to (each retry would be on a
* new random port).
*/
public static final int BIND_RETRIES_DEFAULT_VALUE = 50;
/**
* The name of the property containing the number of binds that a Media
* Service Implementation should execute in case a port is already
* bound to (each retry would be on a new port in the allowed boundaries).
*/
public static final String BIND_RETRIES_PROPERTY_NAME
= "net.java.sip.communicator.service.media.BIND_RETRIES";
/**
* The name of the property that contains the maximum port number that we'd
* like our RTP managers to bind upon.
*/
public static final String MAX_PORT_NUMBER_PROPERTY_NAME
= "net.java.sip.communicator.service.media.MAX_PORT_NUMBER";
/**
* The maximum port number DefaultStreamConnector instances are to
* attempt to bind to.
*/
private static int maxPort = -1;
/**
* The name of the property that contains the minimum port number that we'd
* like our RTP managers to bind upon.
*/
public static final String MIN_PORT_NUMBER_PROPERTY_NAME
= "net.java.sip.communicator.service.media.MIN_PORT_NUMBER";
/**
* The minimum port number DefaultStreamConnector instances are to
* attempt to bind to.
*/
private static int minPort = -1;
/**
* Creates a new DatagramSocket instance which is bound to the
* specified local InetAddress and its port is within the range
* defined by the ConfigurationService properties
* {@link #MIN_PORT_NUMBER_PROPERTY_NAME} and
* {@link #MAX_PORT_NUMBER_PROPERTY_NAME}. Attempts at most
* {@link #BIND_RETRIES_PROPERTY_NAME} times to bind.
*
* @param bindAddr the local InetAddress the new
* DatagramSocket is to bind to
* @return a new DatagramSocket instance bound to the specified
* local InetAddress
*/
private static synchronized DatagramSocket createDatagramSocket(
InetAddress bindAddr)
{
ConfigurationService cfg = LibJitsi.getConfigurationService();
int bindRetries = BIND_RETRIES_DEFAULT_VALUE;
if (cfg != null)
bindRetries = cfg.getInt(BIND_RETRIES_PROPERTY_NAME, bindRetries);
if (maxPort < 0)
{
maxPort = 6000;
if (cfg != null)
maxPort = cfg.getInt(MAX_PORT_NUMBER_PROPERTY_NAME, maxPort);
}
for (int i = 0; i < bindRetries; i++)
{
if ((minPort < 0) || (minPort > maxPort))
{
minPort = 5000;
if (cfg != null)
{
minPort
= cfg.getInt(MIN_PORT_NUMBER_PROPERTY_NAME, minPort);
}
}
int port = minPort++;
try
{
return
(bindAddr == null)
? new DatagramSocket(port)
: new DatagramSocket(port, bindAddr);
}
catch (SocketException se)
{
logger.warn(
"Retrying a bind because of a failure to bind to address "
+ bindAddr
+ " and port "
+ port,
se);
}
}
return null;
}
/**
* The local InetAddress this StreamConnector attempts to
* bind to on demand.
*/
private final InetAddress bindAddr;
/**
* The DatagramSocket that a stream should use for control data
* (e.g. RTCP) traffic.
*/
protected DatagramSocket controlSocket;
/**
* The DatagramSocket that a stream should use for data (e.g. RTP)
* traffic.
*/
protected DatagramSocket dataSocket;
/**
* Whether this DefaultStreamConnector uses rtcp-mux.
*/
protected boolean rtcpmux = false;
/**
* Initializes a new DefaultStreamConnector instance with no
* control and data DatagramSockets.
*
* Suitable for extenders willing to delay the creation of the control and
* data sockets. For example, they could override
* {@link #getControlSocket()} and/or {@link #getDataSocket()} and create
* them on demand.
*/
public DefaultStreamConnector()
{
this(null, null);
}
/**
* Initializes a new DefaultStreamConnector instance with a
* specific bind InetAddress. The new instance is to attempt to
* bind on demand to the specified InetAddress in the port range
* defined by the ConfigurationService properties
* {@link #MIN_PORT_NUMBER_PROPERTY_NAME} and
* {@link #MAX_PORT_NUMBER_PROPERTY_NAME} at most
* {@link #BIND_RETRIES_PROPERTY_NAME} times.
*
* @param bindAddr the local InetAddress the new instance is to
* attempt to bind to
*/
public DefaultStreamConnector(InetAddress bindAddr)
{
this.bindAddr = bindAddr;
}
/**
* Initializes a new DefaultStreamConnector instance which is to
* represent a specific pair of control and data DatagramSockets.
*
* @param dataSocket the DatagramSocket to be used for data (e.g.
* RTP) traffic
* @param controlSocket the DatagramSocket to be used for control
* data (e.g. RTCP) traffic
*/
public DefaultStreamConnector(
DatagramSocket dataSocket,
DatagramSocket controlSocket)
{
this(dataSocket, controlSocket, false);
}
/**
* Initializes a new DefaultStreamConnector instance which is to
* represent a specific pair of control and data DatagramSockets.
*
* @param dataSocket the DatagramSocket to be used for data (e.g.
* RTP) traffic
* @param controlSocket the DatagramSocket to be used for control
* data (e.g. RTCP) traffic
* @param rtcpmux whether rtcpmux is used.
*/
public DefaultStreamConnector(
DatagramSocket dataSocket,
DatagramSocket controlSocket,
boolean rtcpmux)
{
this.controlSocket = controlSocket;
this.dataSocket = dataSocket;
this.bindAddr = null;
this.rtcpmux = rtcpmux;
}
/**
* Releases the resources allocated by this instance in the course of its
* execution and prepares it to be garbage collected.
*
* @see StreamConnector#close()
*/
@Override
public void close()
{
if (controlSocket != null)
controlSocket.close();
if (dataSocket != null)
dataSocket.close();
}
/**
* Returns a reference to the DatagramSocket that a stream should
* use for control data (e.g. RTCP) traffic.
*
* @return a reference to the DatagramSocket that a stream should
* use for control data (e.g. RTCP) traffic
* @see StreamConnector#getControlSocket()
*/
@Override
public DatagramSocket getControlSocket()
{
if ((controlSocket == null) && (bindAddr != null))
controlSocket = createDatagramSocket(bindAddr);
return controlSocket;
}
/**
* Returns a reference to the DatagramSocket that a stream should
* use for data (e.g. RTP) traffic.
*
* @return a reference to the DatagramSocket that a stream should
* use for data (e.g. RTP) traffic
* @see StreamConnector#getDataSocket()
*/
@Override
public DatagramSocket getDataSocket()
{
if ((dataSocket == null) && (bindAddr != null))
dataSocket = createDatagramSocket(bindAddr);
return dataSocket;
}
/**
* Returns a reference to the Socket that a stream should
* use for data (e.g. RTP) traffic.
*
* @return a reference to the Socket that a stream should
* use for data (e.g. RTP) traffic.
*/
@Override
public Socket getDataTCPSocket()
{
return null;
}
/**
* Returns a reference to the Socket that a stream should
* use for control data (e.g. RTCP).
*
* @return a reference to the Socket that a stream should
* use for control data (e.g. RTCP).
*/
@Override
public Socket getControlTCPSocket()
{
return null;
}
/**
* Returns the protocol of this StreamConnector.
*
* @return the protocol of this StreamConnector
*/
@Override
public Protocol getProtocol()
{
return Protocol.UDP;
}
/**
* Notifies this instance that utilization of its DatagramSockets
* for data and/or control traffic has started.
*
* @see StreamConnector#started()
*/
@Override
public void started()
{
}
/**
* Notifies this instance that utilization of its DatagramSockets
* for data and/or control traffic has temporarily stopped. This instance
* should be prepared to be started at a later time again though.
*
* @see StreamConnector#stopped()
*/
@Override
public void stopped()
{
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRtcpmux()
{
return rtcpmux;
}
}