/*
* @(#)SuperCloneableDataSource.java 1.4 02/08/21
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package com.ibm.media.protocol;
import java.io.*;
import java.util.*;
import javax.media.*;
import javax.media.protocol.*;
/**
* This is a utility class that creates clones of a DataSource.
* The CloneableDataSource is itself a DataSource that
* reflects the functionality and type of the input DataSource. The input
* should be of one of the following types: PullDataSource,
* PullBufferDataSource, PushDataSource or PushBufferDataSource.
* The resulting CloneableDataSource will be of the same type.
* To create a clone of this data source, call the <code>getClone()</code>
* method on this object. Any clone created from this DataSource will by Default
* be a PushDataSource or PushBufferDataSource.
* <p>
* The cloned DataSource shares the properties (duration,
* content type, etc.) of the original DataSource.
* <p>
* Calling <code>connect</code>, <code>disconnect</code>,
* <code>start</code>, <code>stop</code> on the CloneableDataSource (master)
* will propagate the same calls to the cloned (slave) DataSources.
*
* This is a class used by the CloneablePullDataSource,
* CloneablePushDataSource, CloneablePullBufferDataSource,
* CloneablePushDataSource and shouldn't be used explicitly by developers.
*
* @see javax.media.protocol.DataSource
* @since JMF 2.0
*/
class SuperCloneableDataSource extends DataSource {
/**
* The DataSource to be cloned.
*/
protected DataSource input;
/**
* An array of adapters where each adapter correspond to a stream in the
* DataSource we are cloning.
*/
public CloneableSourceStreamAdapter[] streamsAdapters;
/* The streams that will be returned by this DataSource and will be used
* by the connected Handler.
*/
public SourceStream[] streams = null;
/**
* The cloned DataSources.
*/
private Vector clones = new Vector();
/**
* Constructor that takes a DataSource object for cloning.
* @param input the DataSource for cloning.
*/
SuperCloneableDataSource(DataSource input) {
this.input = input;
SourceStream[] originalStreams = null;
if (input instanceof PullDataSource)
originalStreams = ((PullDataSource)input).getStreams();
if (input instanceof PushDataSource)
originalStreams = ((PushDataSource)input).getStreams();
if (input instanceof PullBufferDataSource)
originalStreams = ((PullBufferDataSource)input).getStreams();
if (input instanceof PushBufferDataSource)
originalStreams = ((PushBufferDataSource)input).getStreams();
streamsAdapters = new CloneableSourceStreamAdapter[originalStreams.length];
// create a cloneable adapter for each stream
for (int i = 0; i < originalStreams.length; i++)
streamsAdapters[i] = new CloneableSourceStreamAdapter(originalStreams[i]);
}
/**
* Clone the original datasource, returning an object of the type
* <code>PushDataSource</code> or <code>PushBufferDataSource</code>.
* If the original data source was a
* PullDataSource, then this will be a PushDataSource which pushes at
* the same rate at which the CloneableDataSource is being pulled.
* @return a slave DataSource for this DataSource.
*/
javax.media.protocol.DataSource createClone() {
DataSource newSlave;
if ((input instanceof PullDataSource) ||
(input instanceof PushDataSource))
newSlave = new PushDataSourceSlave();
else // input is a Buffer type DataSource
newSlave = new PushBufferDataSourceSlave();
clones.addElement(newSlave);
try {
newSlave.connect();
} catch (IOException e) {
return null;
}
return newSlave;
}
/**
* Get a string that describes the content-type of the media
* that the source is providing.
* <p>
* It is an error to call <CODE>getContentType</CODE> if the source is
* not connected.
*
* @return The name that describes the media content.
*/
public String getContentType() {
return input.getContentType();
}
/**
* Open a connection to the source described by
* the <CODE>MediaLocator</CODE>.
* <p>
*
* The <CODE>connect</CODE> method initiates communication with the source.
*
* @exception IOException Thrown if there are IO problems
* when <CODE>connect</CODE> is called.
*/
public void connect() throws IOException {
input.connect();
}
/**
* Close the connection to the source described by the locator.
* <p>
* The <CODE>disconnect</CODE> method frees resources used to maintain a
* connection to the source.
* If no resources are in use, <CODE>disconnect</CODE> is ignored.
* If <CODE>stop</CODE> hasn't already been called,
* calling <CODE>disconnect</CODE> implies a stop.
*
*/
public void disconnect() {
input.disconnect();
}
/**
* Initiate data-transfer. The <CODE>start</CODE> method must be
* called before data is available.
*(You must call <CODE>connect</CODE> before calling <CODE>start</CODE>.)
*
* @exception IOException Thrown if there are IO problems with the source
* when <CODE>start</CODE> is called.
*/
public void start() throws IOException {
input.start();
}
/**
* Stop the data-transfer.
* If the source has not been connected and started,
* <CODE>stop</CODE> does nothing.
*/
public void stop() throws IOException {
input.stop();
}
/**
* Obtain the collection of objects that
* control the object that implements this interface.
* <p>
*
* If no controls are supported, a zero length
* array is returned.
*
* @return the collection of object controls
*/
public Object[] getControls() {
return input.getControls();
}
/**
* Obtain the object that implements the specified
* <code>Class</code> or <code>Interface</code>
* The full class or interface name must be used.
* <p>
*
* If the control is not supported then <code>null</code>
* is returned.
*
* @return the object that implements the control,
* or <code>null</code>.
*/
public Object getControl(String controlType) {
return input.getControl(controlType);
}
/**
* Get the duration of the media represented
* by this object.
* The value returned is the media's duration
* when played at the default rate.
* If the duration can't be determined (for example, the media object is presenting live
* video) <CODE>getDuration</CODE> returns <CODE>DURATION_UNKNOWN</CODE>.
*
* @return A <CODE>Time</CODE> object representing the duration or DURATION_UNKNOWN.
*/
public Time getDuration() {
return input.getDuration();
}
class PushDataSourceSlave extends PushDataSource {
PushSourceStream[] streams = null;
public PushDataSourceSlave() {
streams = new PushSourceStream[streamsAdapters.length];
for (int i = 0; i < streams.length; i++)
streams[i] = (PushSourceStream)streamsAdapters[i].createSlave();
}
public String getContentType() {
return input.getContentType();
}
public void connect() throws IOException {
for (int i = 0; i < streams.length; i++) {
((SourceStreamSlave)streams[i]).connect();
}
}
public void disconnect() {
for (int i = 0; i < streams.length; i++) {
((SourceStreamSlave)streams[i]).disconnect();
}
}
public void start() throws IOException {
// DO NOTHING SINCE THIS IS A CLONE
}
public void stop() throws IOException {
// DO NOTHING SINCE THIS IS A CLONE
}
public PushSourceStream[] getStreams() {
return streams;
}
public Object[] getControls() {
// should we duplicate the controls?
return input.getControls();
}
public Object getControl(String controlType) {
// should we duplicate the control?
return input.getControl(controlType);
}
public Time getDuration() {
return input.getDuration();
}
}
class PushBufferDataSourceSlave extends PushBufferDataSource {
PushBufferStream[] streams = null;
public PushBufferDataSourceSlave() {
streams = new PushBufferStream[streamsAdapters.length];
for (int i = 0; i < streams.length; i++)
streams[i] = (PushBufferStream)streamsAdapters[i].createSlave();
}
public String getContentType() {
return input.getContentType();
}
public void connect() throws IOException {
for (int i = 0; i < streams.length; i++) {
((SourceStreamSlave)streams[i]).connect();
}
}
public void disconnect() {
for (int i = 0; i < streams.length; i++) {
((SourceStreamSlave)streams[i]).disconnect();
}
}
public void start() throws IOException {
// DO NOTHING SINCE THIS IS A CLONE
}
public void stop() throws IOException {
// DO NOTHING SINCE THIS IS A CLONE
}
public PushBufferStream[] getStreams() {
return streams;
}
public Object[] getControls() {
// should we duplicate the controls?
return input.getControls();
}
public Object getControl(String controlType) {
// should we duplicate the control?
return input.getControl(controlType);
}
public Time getDuration() {
return input.getDuration();
}
}
}
|