Skip to content
Snippets Groups Projects
AbstractRTPConnector.java 13.17 KiB
/*
 * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jitsi.impl.neomedia;

import java.io.*;
import java.net.*;

import javax.media.rtp.*;

import org.jitsi.service.neomedia.*;

/**
 * Provides a base/default implementation of <tt>RTPConnector</tt> which has
 * factory methods for its control and data input and output streams and has an
 * associated <tt>StreamConnector</tt>.
 *
 * @author Bing SU (nova.su@gmail.com)
 * @author Lyubomir Marinov
 */
public abstract class AbstractRTPConnector
    implements RTPConnector
{
    /**
     * The pair of datagram sockets for RTP and RTCP traffic that this instance
     * uses in the form of a <tt>StreamConnector</tt>.
     */
    protected final StreamConnector connector;

    /**
     * RTCP packet input stream used by <tt>RTPManager</tt>.
     */
    private RTPConnectorInputStream controlInputStream;

    /**
     * RTCP packet output stream used by <tt>RTPManager</tt>.
     */
    private RTPConnectorOutputStream controlOutputStream;

    /**
     * RTP packet input stream used by <tt>RTPManager</tt>.
     */
    private RTPConnectorInputStream dataInputStream;

    /**
     * RTP packet output stream used by <tt>RTPManager</tt>.
     */
    private RTPConnectorOutputStream dataOutputStream;

    /**
     * Initializes a new <tt>AbstractRTPConnector</tt> which is to use a given
     * pair of datagram sockets for RTP and RTCP traffic specified in the form
     * of a <tt>StreamConnector</tt>.
     *
     * @param connector the pair of datagram sockets for RTP and RTCP traffic
     * the new instance is to use
     */
    public AbstractRTPConnector(StreamConnector connector)
    {
        if (connector == null)
            throw new NullPointerException("connector");

        this.connector = connector;
    }

    /**
     * Add a stream target. A stream target is the destination address which
     * this RTP session will send its data to. For a single session, we can add
     * multiple SessionAddresses, and for each address, one copy of data will be
     * sent to.
     *
     * @param target Destination target address
     * @throws IOException if there was a socket-related error while adding the
     * specified target
     */
    public void addTarget(SessionAddress target)
        throws IOException
    {
        InetAddress controlAddress = target.getControlAddress();

        if (controlAddress != null)
        {
            getControlOutputStream().addTarget(
                    controlAddress,
                    target.getControlPort());
        }

        getDataOutputStream().addTarget(
                target.getDataAddress(),
                target.getDataPort());
    }

    /**
     * Closes all sockets, stream, and the <tt>StreamConnector</tt> that this
     * <tt>RTPConnector</tt> is using.
     */
    public void close()
    {
        if (dataOutputStream != null)
        {
            dataOutputStream.close();
            dataOutputStream = null;
        }
        if (controlOutputStream != null)
        {
            controlOutputStream.close();
            controlOutputStream = null;
        }
        if (dataInputStream != null)
        {
            dataInputStream.close();
            dataInputStream = null;
        }
        if (controlInputStream != null)
        {
            controlInputStream.close();
            controlInputStream = null;
        }

        connector.close();
    }

    /**
     * Creates the RTCP packet input stream to be used by <tt>RTPManager</tt>.
     *
     * @return a new RTCP packet input stream to be used by <tt>RTPManager</tt>
     * @throws IOException if an error occurs during the creation of the RTCP
     * packet input stream
     */
    protected abstract RTPConnectorInputStream createControlInputStream()
        throws IOException;

    /**
     * Creates the RTCP packet output stream to be used by <tt>RTPManager</tt>.
     *
     * @return a new RTCP packet output stream to be used by <tt>RTPManager</tt>
     * @throws IOException if an error occurs during the creation of the RTCP
     * packet output stream
     */
    protected abstract RTPConnectorOutputStream createControlOutputStream()
        throws IOException;

    /**
     * Creates the RTP packet input stream to be used by <tt>RTPManager</tt>.
     *
     * @return a new RTP packet input stream to be used by <tt>RTPManager</tt>
     * @throws IOException if an error occurs during the creation of the RTP
     * packet input stream
     */
    protected abstract RTPConnectorInputStream createDataInputStream()
        throws IOException;

    /**
     * Creates the RTP packet output stream to be used by <tt>RTPManager</tt>.
     *
     * @return a new RTP packet output stream to be used by <tt>RTPManager</tt>
     * @throws IOException if an error occurs during the creation of the RTP
     * packet output stream
     */
    protected abstract RTPConnectorOutputStream createDataOutputStream()
        throws IOException;

    /**
     * Gets the <tt>StreamConnector</tt> which represents the pair of datagram
     * sockets for RTP and RTCP traffic used by this instance.
     *
     * @return the <tt>StreamConnector</tt> which represents the pair of
     * datagram sockets for RTP and RTCP traffic used by this instance
     */
    public final StreamConnector getConnector()
    {
        return connector;
    }

    /**
     * Returns the input stream that is handling incoming RTCP packets.
     *
     * @return the input stream that is handling incoming RTCP packets.
     *
     * @throws IOException if an error occurs during the creation of the RTCP
     * packet input stream
     */
    public RTPConnectorInputStream getControlInputStream()
        throws IOException
    {
        return getControlInputStream(true);
    }

    /**
     * Gets the <tt>PushSourceStream</tt> which gives access to the RTCP data
     * received from the remote targets and optionally creates it if it does not
     * exist yet.
     *
     * @param create <tt>true</tt> to create the <tt>PushSourceStream</tt> which
     * gives access to the RTCP data received from the remote targets if it does
     * not exist yet; otherwise, <tt>false</tt>
     * @return the <tt>PushBufferStream</tt> which gives access to the RTCP data
     * received from the remote targets; <tt>null</tt> if it does not exist yet
     * and <tt>create</tt> is <tt>false</tt>
     * @throws IOException if creating the <tt>PushSourceStream</tt> fails
     */
    protected RTPConnectorInputStream getControlInputStream(boolean create)
        throws IOException
    {
        if ((controlInputStream == null) && create)
            controlInputStream = createControlInputStream();
        return controlInputStream;
    }

    /**
     * Returns the input stream that is handling outgoing RTCP packets.
     *
     * @return the input stream that is handling outgoing RTCP packets.
     *
     * @throws IOException if an error occurs during the creation of the RTCP
     * packet output stream
     */
    public RTPConnectorOutputStream getControlOutputStream()
        throws IOException
    {
        return getControlOutputStream(true);
    }

    /**
     * Gets the <tt>OutputDataStream</tt> which is used to write RTCP data to be
     * sent to from the remote targets and optionally creates it if it does not
     * exist yet.
     *
     * @param create <tt>true</tt> to create the <tt>OutputDataStream</tt> which
     * is to be used to write RTCP data to be sent to the remote targets if it
     * does not exist yet; otherwise, <tt>false</tt>
     * @return the <tt>OutputDataStream</tt> which is used to write RTCP data to
     * be sent to the remote targets; <tt>null</tt> if it does not exist yet and
     * <tt>create</tt> is <tt>false</tt>
     * @throws IOException if creating the <tt>OutputDataStream</tt> fails
     */
    protected RTPConnectorOutputStream getControlOutputStream(boolean create)
        throws IOException
    {
        if ((controlOutputStream == null) && create)
            controlOutputStream = createControlOutputStream();
        return controlOutputStream;
    }

    /**
     * Returns the input stream that is handling incoming RTP packets.
     *
     * @return the input stream that is handling incoming RTP packets.
     *
     * @throws IOException if an error occurs during the creation of the RTP
     * packet input stream
     */
    public RTPConnectorInputStream getDataInputStream()
        throws IOException
    {
        return getDataInputStream(true);
    }

    /**
     * Gets the <tt>PushSourceStream</tt> which gives access to the RTP data
     * received from the remote targets and optionally creates it if it does not
     * exist yet.
     *
     * @param create <tt>true</tt> to create the <tt>PushSourceStream</tt> which
     * gives access to the RTP data received from the remote targets if it does
     * not exist yet; otherwise, <tt>false</tt>
     * @return the <tt>PushBufferStream</tt> which gives access to the RTP data
     * received from the remote targets; <tt>null</tt> if it does not exist yet
     * and <tt>create</tt> is <tt>false</tt>
     * @throws IOException if creating the <tt>PushSourceStream</tt> fails
     */
    protected RTPConnectorInputStream getDataInputStream(boolean create)
        throws IOException
    {
        if ((dataInputStream == null) && create)
            dataInputStream = createDataInputStream();
        return dataInputStream;
    }

    /**
     * Returns the input stream that is handling outgoing RTP packets.
     *
     * @return the input stream that is handling outgoing RTP packets.
     *
     * @throws IOException if an error occurs during the creation of the RTP
     */
    public RTPConnectorOutputStream getDataOutputStream()
        throws IOException
    {
        return getDataOutputStream(true);
    }

    /**
     * Gets the <tt>OutputDataStream</tt> which is used to write RTP data to be
     * sent to from the remote targets and optionally creates it if it does not
     * exist yet.
     *
     * @param create <tt>true</tt> to create the <tt>OutputDataStream</tt> which
     * is to be used to write RTP data to be sent to the remote targets if it
     * does not exist yet; otherwise, <tt>false</tt>
     * @return the <tt>OutputDataStream</tt> which is used to write RTP data to
     * be sent to the remote targets; <tt>null</tt> if it does not exist yet and
     * <tt>create</tt> is <tt>false</tt>
     * @throws IOException if creating the <tt>OutputDataStream</tt> fails
     */
    public RTPConnectorOutputStream getDataOutputStream(boolean create)
        throws IOException
    {
        if ((dataOutputStream == null) && create)
            dataOutputStream = createDataOutputStream();
        return dataOutputStream;
    }

    /**
     * Provides a dummy implementation to {@link
     * RTPConnector#getReceiveBufferSize()} that always returns <tt>-1</tt>.
     */
    public int getReceiveBufferSize()
    {
        // Not applicable
        return -1;
    }

    /**
     * Provides a dummy implementation to {@link
     * RTPConnector#getRTCPBandwidthFraction()} that always returns <tt>-1</tt>.
     */
    public double getRTCPBandwidthFraction()
    {
        // Not applicable
        return -1;
    }

    /**
     * Provides a dummy implementation to {@link
     * RTPConnector#getRTCPSenderBandwidthFraction()} that always returns
     * <tt>-1</tt>.
     */
    public double getRTCPSenderBandwidthFraction()
    {
        // Not applicable
        return -1;
    }

    /**
     * Provides a dummy implementation to {@link
     * RTPConnector#getSendBufferSize()} that always returns <tt>-1</tt>.
     */
    public int getSendBufferSize()
    {
        // Not applicable
        return -1;
    }

    /**
     * Removes a target from our session. If a target is removed, there will be
     * no data sent to that address.
     *
     * @param target Destination target to be removed
     */
    public void removeTarget(SessionAddress target)
    {
        if (controlOutputStream != null)
            controlOutputStream
                .removeTarget(
                    target.getControlAddress(),
                    target.getControlPort());

        if (dataOutputStream != null)
            dataOutputStream
                .removeTarget(
                    target.getDataAddress(),
                    target.getDataPort());
    }

    /**
     * Remove all stream targets. After this operation is done. There will be
     * no targets receiving data, so no data will be sent.
     */
    public void removeTargets()
    {
        if (controlOutputStream != null)
            controlOutputStream.removeTargets();

        if (dataOutputStream != null)
            dataOutputStream.removeTargets();
    }

    /**
     * Provides a dummy implementation to {@link
     * RTPConnector#setReceiveBufferSize(int)}.
     *
     * @param size ignored.
     */
    public void setReceiveBufferSize(int size)
        throws IOException
    {
        // Nothing should be done here :-)
    }

    /**
     * Provides a dummy implementation to {@link
     * RTPConnector#setSendBufferSize(int)}.
     *
     * @param size ignored.
     */
    public void setSendBufferSize(int size)
        throws IOException
    {
        // Nothing should be done here :-)
    }
}