/*
* 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.impl.resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import org.mobicents.media.Buffer;
import org.mobicents.media.Format;
import org.mobicents.media.MediaSink;
import org.mobicents.media.MediaSource;
import org.mobicents.media.Outlet;
import org.mobicents.media.server.impl.AbstractSink;
import org.mobicents.media.server.impl.AbstractSinkSet;
import org.mobicents.media.server.impl.AbstractSource;
import org.mobicents.media.server.spi.Connection;
import org.mobicents.media.server.spi.Endpoint;
import org.mobicents.media.server.spi.SyncSource;
/**
* Combines several signals for transmission over a single medium. A
* demultiplexor completes the process by separating multiplexed signals from a
* transmission line. Frequently a multiplexor and demultiplexor are combined
* into a single device capable of processing both outgoing and incoming
* signals.
* <br>Multiplexer combines data and sends them, it is used as output for components.
* @author Oleg Kulikov
*/
public class Multiplexer extends AbstractSinkSet implements Outlet, SyncSource {
private Format[] inputFormats = null;
private Output output;
private Buffer buff;
private long timestamp;
/**
* Creates new instance of multiplexer.
*
* @param name the name of the multiplexer to be created.
*/
public Multiplexer(String name) {
super(name);
output = new Output(name);
output.setSyncSource(this);
}
public void connect(MediaSink sink) {
output.connect(sink);
}
public void disconnect(MediaSink sink) {
output.disconnect(sink);
}
@Override
public AbstractSink createSink(MediaSource otherParty) {
Input input = new Input(getName() + "[input]");
input.setEndpoint(getEndpoint());
input.setConnection(getConnection());
return input;
}
@Override
public void start() {
output.start();
}
@Override
public void stop() {
output.stop();
}
/**
* This method allows to access identifier from the inner source
* and sink implemetation.
*
* @return the unique identifer of this component.
*/
private String getIdentifier() {
return getId();
}
/**
* (Non Java-doc).
*
* @see org.mobicents.media.Outlet#getOutput().
*/
public MediaSource getOutput() {
return output;
}
/**
* (Non Java-doc).
*
* @see org.mobicents.media.MediaSource#getFormats().
*/
public Format[] getFormats() {
return output.getOtherPartyFormats();
}
@Override
public void setConnection(Connection connection) {
super.setConnection(connection);
output.setConnection(connection);
Collection<AbstractSink> streams = getStreams();
for (AbstractSink stream : streams) {
stream.setConnection(connection);
}
}
@Override
public void setEndpoint(Endpoint endpoint) {
super.setEndpoint(endpoint);
output.setEndpoint(endpoint);
Collection<AbstractSink> list = getStreams();
for (AbstractSink stream : list) {
stream.setEndpoint(endpoint);
}
}
/**
* Reassemblies the list of used formats. This method is called each time
* when connected/disconnected source
*/
private void reassemblyFormats() {
ArrayList list = new ArrayList();
Collection<AbstractSink> streams = getStreams();
for (AbstractSink stream : streams) {
Format[] fmts = ((Input)stream).getOtherPartyFormats();
for (Format format : fmts) {
if (!list.contains(format)) {
list.add(format);
}
}
}
inputFormats = new Format[list.size()];
list.toArray(inputFormats);
}
/**
* (Non Java-doc).
*
* @see org.mobicents.media.MediaSink#isAcceptable(org.mobicents.media.Format)
*/
public boolean isAcceptable(Format fmt) {
return output.isAcceptable(fmt);
}
/**
* Implement input stream.
*/
class Input extends AbstractSink {
/**
* Creates new input.
*
* @param name the name of parent MUX.
*/
public Input(String name) {
super(name);
}
@Override
public String getId() {
return getIdentifier();
}
/**
* (Non Java-doc).
*
* @see org.mobicents.media.MediaSink#isAcceptable(org.mobicents.media.Format)
*/
public boolean isAcceptable(Format fmt) {
return output.isAcceptable(fmt);
}
/**
* (Non Java-doc).
*
* @see org.mobicents.media.server.impl.AbstractSink#onMediaTransfer(org.mobicents.media.Buffer).
*/
public void onMediaTransfer(Buffer buffer) throws IOException {
buff = buffer;
timestamp = buffer.getTimeStamp();
output.run();
}
/**
* (Non Java-doc).
*
* @see org.mobicents.media.MediaSink#getFormats().
*/
public Format[] getFormats() {
return output.getOtherPartyFormats();
}
/**
* Reads supported formats from other party if connected.
*
* @return if other party connected returns array of supported formats
* or empty array if not connected.
*/
protected Format[] getOtherPartyFormats() {
return otherParty.getFormats();
}
}
class Output extends AbstractSource {
private volatile boolean stopped = true;
/**
* Creates Ouput.
*
* @param name the name of parent MUX.
*/
public Output(String name) {
super(name);
}
@Override
public void start() {
stopped = false;
}
@Override
public void stop() {
stopped = true;
}
/**
* (Non Java-doc).
*
* @see org.mobicents.media.MediaSource#getFormats().
*/
public Format[] getFormats() {
reassemblyFormats();
return inputFormats;
}
/**
* Checks is other party supports specofied format.
*
* @param fmt the format to check
* @return true if other party supports this format.
*/
public boolean isAcceptable(Format fmt) {
return otherParty != null && otherParty.isAcceptable(fmt);
}
/**
* Gets list of formats supported by other party.
*
* @return array of formats or empty array if not connected yet.
*/
public Format[] getOtherPartyFormats() {
return otherParty != null ? otherParty.getFormats() : new Format[0];
}
@Override
public void evolve(Buffer buffer, long timestamp, long sequenceNumber) {
if (!stopped) {
buffer.copy(buff);
}
}
}
@Override
public void onMediaTransfer(Buffer buffer) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void destroySink(AbstractSink sink) {
}
public void sync(MediaSource mediaSource) {
}
public void unsync(MediaSource mediaSource) {
}
public long getTimestamp() {
return timestamp;
}
}