/*
* Mobicents, Communications Middleware
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party
* contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
*
* Boston, MA 02110-1301 USA
*/
package org.mobicents.media.server;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.concurrent.locks.ReentrantLock;
import javax.sdp.SdpFactory;
import org.apache.log4j.Logger;
import org.mobicents.media.Component;
import org.mobicents.media.ComponentFactory;
import org.mobicents.media.MediaSink;
import org.mobicents.media.MediaSource;
import org.mobicents.media.server.impl.resource.audio.EndpointTransmittor;
import org.mobicents.media.server.impl.rtp.RtpFactory;
import org.mobicents.media.server.resource.Channel;
import org.mobicents.media.server.resource.ChannelFactory;
import org.mobicents.media.server.spi.Connection;
import org.mobicents.media.server.spi.ConnectionListener;
import org.mobicents.media.server.spi.ConnectionMode;
import org.mobicents.media.server.spi.Endpoint;
import org.mobicents.media.server.spi.NotificationListener;
import org.mobicents.media.server.spi.ResourceGroup;
import org.mobicents.media.server.spi.ResourceUnavailableException;
import org.mobicents.media.server.spi.Timer;
import org.mobicents.media.server.spi.TooManyConnectionsException;
/**
*
* @author kulikov
*/
public class EndpointImpl implements Endpoint {
private String localName;
private boolean isInUse = false;
private Timer timer;
private ComponentFactory sourceFactory;
private ComponentFactory sinkFactory;
private ComponentFactory groupFactory;
private ConnectionFactory connectionFactory;
private Hashtable<String, RtpFactory> rtpFactory;
private MediaSource source;
private MediaSink sink;
private ResourceGroup resourceGroup;
/** The list of indexes available for connection enumeration within endpoint */
private ArrayList<Integer> index = new ArrayList();
/** The last generated connection's index*/
private int lastIndex = -1;
/** Holder for created connections */
protected transient HashMap<String, Connection> connections = new HashMap();
protected ReentrantLock state = new ReentrantLock();
private SdpFactory sdpFactory = SdpFactory.getInstance();
private HashMap <String, EndpointTransmittor> transmittors = new HashMap();
private final Logger logger = Logger.getLogger(EndpointImpl.class);
public EndpointImpl() {
}
public EndpointImpl(String localName) {
this.localName = localName;
}
public String getLocalName() {
return localName;
}
public void setLocalName(String localName) {
this.localName = localName;
}
public MediaSink getSink() {
return sink;
}
public MediaSource getSource() {
return source;
}
/**
* Calculates index of the new connection.
*
* The connection uses this method to ask endpoint for new lowerest index.
* The index is unique withing endpoint but it is not used as connection
* identifier outside of the endpoint.
*
* @return the lowerest available integer value.
*/
protected int getIndex() {
return index.isEmpty() ? ++lastIndex : index.remove(0);
}
public void start() throws ResourceUnavailableException {
if (sourceFactory != null) {
source = (MediaSource) sourceFactory.newInstance(this);
source.setEndpoint(this);
}
if (sinkFactory != null) {
sink = (MediaSink) sinkFactory.newInstance(this);
sink.setEndpoint(this);
}
if (groupFactory != null) {
resourceGroup = (ResourceGroup) groupFactory.newInstance(this);
sink = resourceGroup.getSink();
sink.setEndpoint(this);
source = resourceGroup.getSource();
source.setEndpoint(this);
}
logger.info("Started " + localName);
}
public void stop() {
logger.info("Stopped " + localName);
}
protected SdpFactory getSdpFactory() {
return sdpFactory;
}
public Timer getTimer() {
return timer;
}
public void setTimer(Timer timer) {
this.timer = timer;
}
public void setSourceFactory(ComponentFactory sourceFactory) {
this.sourceFactory = sourceFactory;
}
public ComponentFactory getSourceFactory() {
return sourceFactory;
}
public void setSinkFactory(ComponentFactory sinkFactory) {
this.sinkFactory = sinkFactory;
}
public ComponentFactory getSinkFactory() {
return sinkFactory;
}
public ComponentFactory getGroupFactory() {
return groupFactory;
}
public void setGroupFactory(ComponentFactory groupFactory) {
this.groupFactory = groupFactory;
}
public ConnectionFactory getConnectionFactory() {
return connectionFactory;
}
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public void setRtpFactory(Hashtable<String, RtpFactory> rtpFactory) {
this.rtpFactory = rtpFactory;
}
public Hashtable<String, RtpFactory> getRtpFactory() {
return this.rtpFactory;
}
protected Channel createRxChannel(Connection connection) throws ResourceUnavailableException {
ChannelFactory rxChannelFactory = connectionFactory.getRxChannelFactory();
if (rxChannelFactory != null && sink != null) {
Channel rxChannel = rxChannelFactory.newInstance(this);
rxChannel.setConnection(connection);
rxChannel.setEndpoint(this);
rxChannel.connect(sink);
// rxChannel.connect(rxLocalChannel);
sink.start();
return rxChannel;
} else return null;
}
protected void releaseRxChannel(Channel channel) {
if (channel != null && sink != null) {
channel.disconnect(sink);
channel.setConnection(null);
channel.setEndpoint(null);
ChannelFactory rxChannelFactory = connectionFactory.getRxChannelFactory();
rxChannelFactory.release(channel);
}
}
protected Channel createTxChannel(Connection connection) throws ResourceUnavailableException {
ChannelFactory txChannelFactory = connectionFactory.getTxChannelFactory();
if (txChannelFactory != null && source != null) {
Channel txChannel = txChannelFactory.newInstance(this);
txChannel.setEndpoint(this);
txChannel.setConnection(connection);
EndpointTransmittor transmittor = new EndpointTransmittor("Endpoint[output]", getTimer());
transmittor.setEndpoint(this);
transmittor.setConnection(connection);
transmittor.getInput().connect(source);
txChannel.connect(transmittor.getOutput());
transmittor.start();
transmittors.put(connection.getId(), transmittor);
// txChannel.connect(source);
return txChannel;
} else return null;
}
protected void releaseTxChannel(Channel channel) {
if (channel != null && source != null) {
EndpointTransmittor transmittor = transmittors.remove(channel.getConnection().getId());
transmittor.stop();
transmittor.getInput().disconnect(source);
channel.disconnect(transmittor.getOutput());
channel.setConnection(null);
channel.setEndpoint(null);
ChannelFactory txChannelFactory = connectionFactory.getTxChannelFactory();
txChannelFactory.release(channel);
}
}
public Collection<Connection> getConnections() {
return connections.values();
}
public Connection createConnection(ConnectionMode mode) throws TooManyConnectionsException, ResourceUnavailableException {
state.lock();
try {
if (logger.isDebugEnabled()) {
logger.debug(getLocalName() + ", creating RTP connection, mode=" + mode);
}
RtpConnectionImpl connection = new RtpConnectionImpl(this, mode);
connections.put(connection.getId(), connection);
this.isInUse = true;
return connection;
} catch (Exception e) {
logger.error("Could not create RTP connection", e);
throw new ResourceUnavailableException(e.getMessage());
} finally {
state.unlock();
}
}
public Connection createLocalConnection(ConnectionMode mode) throws TooManyConnectionsException, ResourceUnavailableException {
state.lock();
try {
if (logger.isDebugEnabled()) {
logger.debug(getLocalName() + ", creating Local connection, mode=" + mode);
}
LocalConnectionImpl connection = new LocalConnectionImpl(this, mode);
connections.put(connection.getId(), connection);
this.isInUse = true;
return connection;
} catch (Exception e) {
logger.error("Could not create Local connection", e);
throw new ResourceUnavailableException(e.getMessage());
} finally {
state.unlock();
}
}
public void deleteConnection(String connectionID) {
state.lock();
try {
ConnectionImpl connection = (ConnectionImpl) connections.remove(connectionID);
if (connection != null) {
if (logger.isDebugEnabled()) {
logger.debug(getLocalName() + ", Deleting connection " + connection.getIndex());
}
connection.close();
index.add(connection.getIndex());
}
isInUse = connections.size() > 0;
} finally {
state.unlock();
}
}
/**
* (Non Java-doc).
*
* @see org.mobicents.media.server.spi.Endpoint#deleteAllConnections();
*/
public void deleteAllConnections() {
state.lock();
try {
ConnectionImpl[] list = new ConnectionImpl[connections.size()];
connections.values().toArray(list);
for (int i = 0; i < list.length; i++) {
deleteConnection(list[i].getId());
}
} finally {
state.unlock();
}
}
public boolean hasConnections() {
return !connections.isEmpty();
}
public boolean isInUse() {
return this.isInUse;
}
public void setInUse(boolean inUse) {
this.isInUse = inUse;
}
public void addNotificationListener(NotificationListener listener) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void removeNotificationListener(NotificationListener listener) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void addConnectionListener(ConnectionListener listener) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void removeConnectionListener(ConnectionListener listener) {
throw new UnsupportedOperationException("Not supported yet.");
}
public String[] getSupportedPackages() {
throw new UnsupportedOperationException("Not supported yet.");
}
public Connection getConnection(String connectionID) {
return connections.get(connectionID);
}
public Component getComponent(String name) {
if (source != null && source.getName().matches(name)) {
return source;
} else if (sink != null && sink.getName().matches(name)) {
return sink;
}
return null;
}
public Component getComponent(int resourceID) {
throw new UnsupportedOperationException("Not supported yet.");
}
}