FileDocCategorySizeDatePackage
Manager.javaAPI DocJMF 2.1.1e79626Mon May 12 12:20:36 BST 2003javax.media

Manager

public final class Manager extends Object
Manager is the access point for obtaining system dependent resources such as Players, DataSources, Processors, DataSinks, the system TimeBase, the cloneable and merging utility DataSources.

A DataSource is an object used to deliver time-based multimedia data that is specific to a delivery protocol.

A Player is an object used to control and render multimedia data that is specific to the content type of the data.

A Processor is an object similar to a Player which is used to process data and output the processed data.

A DataSink is an object that takes a DataSource as input and renders the output to a specified destination.

A DataSource provides a Player, Processor or DataSink with media data; a Player, Processor or DataSink must have a DataSource. Manager provides access to a protocol and media independent mechanism for constructing DataSources, Players, Processors and DataSinks.

Creating Players and DataSources

Manager will createPlayers from a URL, a MediaLocator or a DataSource. Creating a Player requires the following:
  • Obtain the connected DataSource for the specified protocol
  • Obtain the Player for the content-type specified by the DataSource
  • Attach the DataSource to the Player using the setSource method.

Finding DataSources by Protocol

A MediaLocator defines a protocol for obtaining content. DataSources are identified by the protocol that they support. Manager uses the protocol name to find DataSource classes.

To find a DataSource using a MediaLocator, Manager constructs a list of class names from the protocol package-prefix list and the protocol name obtained from the MediaLocator. For each class name in the constructed list a new DataSource is instantiated, the MediaLocator is attached, and the DataSource is connected. If no errors have occurred, the procces is considered finished and the connected DataSource is used by Manager in any following operations. If there was an error then the next class name in the list is tried. The exact details of the search algorithm is described in the method documentation below.

Finding Players by Content Type

A Player is a MediaHandler. A MediaHandler is a an object that reads data from a DataSource. There are three types of supported MediaHandler: MediaProxy, Player and Processor.

MediaHandlers are identified by the content type that they support. A DataSource identifies the content type of the data it produces with the getContentType method. Manager uses the content type name to find instances of MediaHandler.

To find a MediaHandler using a content type name, Manager constructs a list of class names from the content package-prefix list and the content type name. For each class name in the constructed list a new MediaHandler is instantiated, and the DataSource is attached to the MediaHandler using MediaHandler.setSource.

If the MediaHandler is a Player and the setSource was successful the process is finished and the Player is returned. If the setSource failed, another name in the list is tried.

If the MediaHandler is a MediaProxy then a new DataSource is obtained from the MediaProxy, a new list is created for the content type the DataSource supports and the whole thing is tried again.

If a valid Player is not found then the whole procedure is repeated with "unknown" substituted for the content-type name. The "unknown" content type is supported by generic Players that are capable of handling a large variety of media types, often in a platform dependent way.

The detailed creation algorithm is specified in the methods below.

Creating a Realized Player

Versions of createRealizedPlayer calls are provided as an acceleration to create a Player. The returned player is in the Realized state. In addition to NoPlayerException and IOException, CannotRealizeException can be thrown if the Manager cannot realize the Player.

Creating Processors

Processors are created in the same way as Players as outlined above. Manager also provides an additional way to create a Processor via the createRealizedProcessor call. A ProcessorModel is used to fully identify the input and output requirements of a Processor. The createRealizedProcessor call takes a ProcessorModel as input and create a Processor that adheres to the given ProcessorModel. The returned Processor is in the Realized state. The method is a blocking call.

If the Manager fails to find a Processor that fits the ProcessorModel, a NoProcessorException is thrown. If there is a problem creating and realizing a Processor, it will throw an IOException or CannotRealizeException depending on the circumstances.

Creating DataSinks

DataSinks are created from an input DataSource MediaLocator. The MediaLocator identifies the protocol and content of the DataSink to be used. The search for the particular DataSink class to be created is similar to the process of creating a DataSource. The detail search and creation algorithm is described in the method documentation below.

Player and Processor Threads

Players and Processors process media data asynchronously from the main program flow. This implies that a Player or Processor must often manage one or more threads. The threads managed by the Player or Processor are not in the thread group of the application that calls createPlayer or createProcessor.

System Time Base

All Players need a TimeBase. Many use a system-wide TimeBase, often based on a time-of-day clock. Manager provides access to the system TimeBase through getSystemTimeBase.

Cloning and Merging DataSources

DataSources can be cloned or merged. If a DataSource is cloned, more than one MediaHandler can use it as input. Merging more than one DataSources will generate one DataSource which contains all the SourceStreams of the constituent DataSources

The Manager provides two methods: createCloneableDataSource and createMergingDataSource for such purpose.

Manager Hints

Using the setHint method, the preference for how the Manager creates the objects can be specified. However, a particular implementation of the Manager can choose to ignore the requested hints.
see
#MAX_SECURITY
see
#CACHING
see
#LIGHTWEIGHT_RENDERER
see
#PLUGIN_PLAYER

since
1.0 , new methods added in 2.0
see
java.net.URL
see
MediaLocator
see
PackageManager
see
javax.media.protocol.DataSource
see
javax.media.protocol.URLDataSource
see
MediaHandler
see
Player
see
Processor
see
MediaProxy
see
TimeBase
version
2.0, 98/05/18.

Fields Summary
private static String
VERSION
public static final int
MAX_SECURITY
Boolean hint to turn on/off maximum security.
public static final int
CACHING
Boolean hint to turn on/off the use of playback caching.
public static final int
LIGHTWEIGHT_RENDERER
Boolean hint to turn on/off the use of light weight rendering. If on, the Manager will try to create Players that use renderers which can interoperate with light weight GUI components.
public static final int
PLUGIN_PLAYER
Boolean hint to request the Manager to create Players that support PlugIns. Such Players use PlugIns to demultiplex, decode, render or multiplex the data. It will also support TrackControls for application level programming.
private static int
numberOfHints
private static SystemTimeBase
sysTimeBase
public static final String
UNKNOWN_CONTENT_NAME
private static boolean
jdkInit
private static Method
forName3ArgsM
private static Method
getSystemClassLoaderM
private static ClassLoader
systemClassLoader
private static Method
getContextClassLoaderM
private static String
fileSeparator
private static Hashtable
hintTable
static final int
DONE
static final int
SUCCESS
Constructors Summary
private Manager()
This private constructor keeps anyone from actually getting a Manager.

     
	/* Default values for the hints */
	hintTable.put(new Integer(MAX_SECURITY), new Boolean(false));
	hintTable.put(new Integer(CACHING), new Boolean(true));
	hintTable.put(new Integer(LIGHTWEIGHT_RENDERER), new Boolean(false));
	hintTable.put(new Integer(PLUGIN_PLAYER), new Boolean(false));
    
Methods Summary
private static voidblockingCall(javax.media.Player p, int state)
Realize a player or processor. It blocks until the player is realized or if the realize fails. Throws a CannotRealizeException if the realize fails.


                                  
             

	// Use this sort of as a pass-by-reference variable.
	boolean sync[] = new boolean[2];
	ControllerListener cl;

	sync[DONE] = false;
	sync[SUCCESS] = false;
	cl = new MCA(sync, state);

	p.addControllerListener(cl);
	if (state == Controller.Realized)
	    p.realize();
	else if (state == Processor.Configured)
	    ((Processor)p).configure();

	// Wait for notification from the controller.
	synchronized (sync) {
	    while (!sync[DONE]) {
		try {
		    sync.wait();
		} catch (InterruptedException e) {}
	    }
	}

	p.removeControllerListener(cl);
	if (!sync[SUCCESS])
	    throw new CannotRealizeException();
    
static java.util.VectorbuildClassList(java.util.Vector prefixList, java.lang.String name)
Build a list of complete class names.

For each element of the prefix-list the following element is added to the list:

<prefix>.<name>
These are added to the list in the same order as the prefixes appear in the prefix-list.

param
prefixList The list of prefixes to prepend to the class name.
param
name The name of the class to build the list for.
return
A vector of class name strings.

	
	// New list which has the name as the first element ...
	Vector classList = new Vector();

	// Try and instance one directly from the classpath
	// if it's there.
	// $jdr: This has been objected to as confusing,
	// the argument for it's inclusion is that it
	// gives the user (via the classpath) a way
	// of modifying the search list at run time
	// for all applications.
	classList.addElement(name);

	// ... for each prefix append the name and put it
	// in the class list ...
	Enumeration prefix = prefixList.elements();
	while( prefix.hasMoreElements()) {
	    String prefixName = (String)prefix.nextElement();
	    classList.addElement(prefixName + "." + name);
	}

	// ... done
	return classList;
    
private static booleancheckIfJDK12()

	if (jdkInit)
	    return (forName3ArgsM != null);
	jdkInit = true;
	try {
	    forName3ArgsM = Class.class.getMethod("forName",
						  new Class[] {
		String.class, boolean.class, ClassLoader.class
		    });
	    
	    getSystemClassLoaderM = ClassLoader.class.getMethod("getSystemClassLoader", null);

	    // TODO: may need to invoke RuntimePermission("getClassLoader") privilege
	    systemClassLoader = (ClassLoader) getSystemClassLoaderM.invoke(ClassLoader.class, null);

	    getContextClassLoaderM = Thread.class.getMethod("getContextClassLoader", null);

	    return true;
	} catch (Throwable t) {
	    forName3ArgsM = null;
	    return false;
	}
    
public static javax.media.protocol.DataSourcecreateCloneableDataSource(javax.media.protocol.DataSource source)


	if (source instanceof SourceCloneable)
	    return source;

	
	if (source instanceof CaptureDevice) {
	    // the created clone will support CaptureDevice interface
	    if (source instanceof javax.media.protocol.PullDataSource) 
		return reflectDS("com.ibm.media.protocol.CloneableCapturePullDataSource", source);
	    
	    if (source instanceof javax.media.protocol.PushDataSource) 
		return reflectDS("com.ibm.media.protocol.CloneableCapturePushDataSource", source);
	    
	    if (source instanceof javax.media.protocol.PullBufferDataSource)
		return reflectDS("com.ibm.media.protocol.CloneableCapturePullBufferDataSource", source);
	    
	    if (source instanceof javax.media.protocol.PushBufferDataSource)
		return reflectDS("com.ibm.media.protocol.CloneableCapturePushBufferDataSource", source);
	}
	
	// Otherwise create a regular non-capture DataSource
	if (source instanceof javax.media.protocol.PullDataSource) 
	    return reflectDS("com.ibm.media.protocol.CloneablePullDataSource", source);
	
	if (source instanceof javax.media.protocol.PushDataSource) 
	    return reflectDS("com.ibm.media.protocol.CloneablePushDataSource", source);

	if (source instanceof javax.media.protocol.PullBufferDataSource) 
	    return reflectDS("com.ibm.media.protocol.CloneablePullBufferDataSource", source);
	
	if (source instanceof javax.media.protocol.PushBufferDataSource)
	    return reflectDS("com.ibm.media.protocol.CloneablePushBufferDataSource", source);
	
	return null;
    
public static javax.media.DataSinkcreateDataSink(javax.media.protocol.DataSource datasource, javax.media.MediaLocator destLocator)
Create a DataSink for the specified input Datasource and destination Medialocator.

The algorithm for creating a DataSink from a MediaLocator and datasource is:

  1. Get the protocol from the MediaLocator.
  2. Get a list of MediaHandler classes within the datasink package that support the protocol, using the content package-prefix-list. i.e. search for content-prefix.media.datasink.protocol.Handler
  3. For each MediaHandler class in the list:
    1. Instantiate a new MediaHandler.
    2. If the MediaHandler is a DataSink, Attach the source to the MediaHandler by calling MediaHandler.setSource
    3. If there are no failures, return this DataSink;otherwise try the next MediaHandler in the list.
    4. If the MediaHandler is a DataSinkProxy, obtain the content type of the proxy using the getContentType() method. Now obtain a list of MediaHandlers that support the protocol of the Medialocator and the content type returned by the proxy
      i.e. look for content-prefix.media.datasink.protocol.content-type.Handler
    5. If a MediaHandler is found and it is a DataSink, attach the datasource to it by calling MediaHandler.setSource.
    6. Return the DataSink if there are no errors.
    7. If no MediaHandler is found, or if there are any errors,try the next MediaHandler
    8. If no DataSink is found after trying all of the handlers, a NoDataSinkException is thrown.

param
datasource The input DataSource to the DataSink
param
destLocator A MediaLocator that describes the destination of the media to be handled by the datasink
return
A DataSink for the media described by the destLocator and that supports the datasource .
exception
NoDataSinkException Thrown if no DataSink can be found.
see
NoDataSinkException


	String handlerName = "media.datasink." + destLocator.getProtocol() +
	                     ".Handler";

	Vector classList = buildClassList(getContentPrefixList(), handlerName);

	Enumeration handlerList = classList.elements();

	DataSink dataSink = null;
	boolean done = false;
	while (!done && handlerList.hasMoreElements()) {
	    String handlerClassName = (String)handlerList.nextElement();
	    try {
		
		// ... try and instance the handler ...
		Class handlerClass = getClassForName(handlerClassName);
		Object object =  handlerClass.newInstance();
		// ... set the DataSource on it ...
		if (object instanceof DataSink) {
		    dataSink = (DataSink) object;
		    dataSink.setSource(datasource);
		    dataSink.setOutputLocator(destLocator);
		    done = true;
		    break; // we are done
		}


		// Otherwise it must be a DataSinkProxy
		// Get a new data source, and content type  ...
		DataSinkProxy dsProxy = (DataSinkProxy) object;
		String contentType = dsProxy.getContentType(destLocator);
		// .. recurse to try and create a Player with it.

		handlerName = "media.datasink." + destLocator.getProtocol() +
		    "." +
		    contentType +
		    ".Handler";

		Vector dataSinkList = buildClassList(getContentPrefixList(), handlerName);
		Enumeration elements = dataSinkList.elements();
		
		while (elements.hasMoreElements()) {
		    String dsClassName = (String) elements.nextElement();
		    try {
			dataSink = (DataSink) getClassForName(dsClassName).newInstance();
			// ... set the DataSource on it ...
			dataSink.setSource(datasource);
			dataSink.setOutputLocator(destLocator);
			done = true;
			break; // we are done
		    } catch (Exception e) {
			dataSink = null;
		    }
		}
		
	    } catch (Exception e) {
		dataSink = null;
	    } catch (Error e) {
		dataSink = null;
	    }
	}
	if ( dataSink == null )
	    throw new NoDataSinkException("Cannot find a DataSink for: " + datasource);

	Log.comment("DataSink created: " + dataSink);
	Log.comment("  using DataSource: " + datasource + "\n");

	return dataSink;
    
public static javax.media.protocol.DataSourcecreateDataSource(java.net.URL sourceURL)
Create a DataSource for the specified media.

param
sourceURL The URL that describes the media data.
return
A new DataSource for the media.
exception
NoDataSourceException Thrown if no DataSource can be found.
exception
IOException Thrown if there was a problem connecting with the source.

	return
	    createDataSource(new MediaLocator(sourceURL));
    
public static javax.media.protocol.DataSourcecreateDataSource(javax.media.MediaLocator sourceLocator)
Create a DataSource for the specified media.

Returns a data source for the protocol specified by the MediaLocator. The returned data source is connected; DataSource.connect has been invoked.

The algorithm for creating a DataSource from a MediaLocator is:

  1. Get the protocol from the MediaLocator.
  2. Use the protocol package-prefix list to get a list of DataSource classes that support the protocol.
  3. For each source class in the list:
    1. Instantiate a new DataSource.
    2. Call connect to connect the source.
    3. If there are no errors, return the connected source; otherwise, try the next source in the list.
  4. If no source has been found, obtain a URL from the MediaLocator and use it to create a URLDataSource
  5. If no source can be found, a NoDataSourceException is thrown.

param
sourceLocator The source protocol for the media data.
return
A connected DataSource.
exception
NoDataSourceException Thrown if no DataSource can be found.
exception
IOException Thrown if there was a problem connecting with the source.


	DataSource source = null;

	// For each DataSource that implements the protocol
        // that's specified in the source locator ....
	Enumeration protoList =
	    getDataSourceList(sourceLocator.getProtocol()).elements();
	while(protoList.hasMoreElements()) {
	    
	    String protoClassName = (String)protoList.nextElement();
	    try {

		// ... Try and instance a DataSource ....
		Class protoClass = getClassForName(protoClassName);
		source = (DataSource)protoClass.newInstance();

		// ... and get it connected ....
		source.setLocator(sourceLocator);
		source.connect();

		//  ... o.k. we've found one, so we're done.
		break;
		
	    } catch (ClassNotFoundException e) {
		// try another data source.
		source = null;
	    } catch (InstantiationException e) {
		// try another data source.
		source = null;
	    } catch (IllegalAccessException e) {
		// try another data source.
		source = null;
	    } catch (Exception e) {
		source = null;
		String err = "Error instantiating class: " + protoClassName + " : " + e;
		Log.error(e);
		throw new NoDataSourceException(err);
	    } catch (Error e) {
		source = null;
		String err = "Error instantiating class: " + protoClassName + " : " + e;
		Log.error(e);
		throw new NoDataSourceException(err);
	    }
	}
	
	// If we haven't found one installed,
	// we'll try and create one from a URL/URLDataSource.
// TEMPORARILY COMMENTED OUT URLDataSource: 1/15/99
// 	if( source == null) {
// 	    try {
// 		source = new URLDataSource(sourceLocator.getURL());
// 		source.connect();
// 	    } catch(MalformedURLException me) {
// 		// Can't get a URL so we're done.
// 		source = null;
// 	    }
// 	}
	
        // If we still haven't found one, we're done
	// and we don't have a source.
	if( source == null) {
	    throw new NoDataSourceException("Cannot find a DataSource for: " + sourceLocator);
	}

	Log.comment("DataSource created: " + source + "\n");

	return source;
    
public static javax.media.protocol.DataSourcecreateMergingDataSource(javax.media.protocol.DataSource[] sources)
Creates a merged DataSource from an array of sources. All sources must be of the same type (i.e PullDataSource, PushDataSource, etc.) otherwise an IncompatibleSourceException is thrown. The returned DataSource is of the same type of the given sources. Its content-type is RAW if all sources are of type RAW. Otherwise, its content-type is MIXED.

param
sources the DataSources to be merged
return
a DataSource which contains all the streams of the original sources
exception
IncompatibleSourceException if the sources are not of the same type

	
	// check if the sources type matches
	if (sources.length == 0)
	    throw new IncompatibleSourceException("No sources");

	if (sources[0] instanceof PullDataSource) {
	    for (int i = 1; i < sources.length; i ++) {
		if (!(sources[i] instanceof PullDataSource))
		    throw new IncompatibleSourceException("One of the sources isn't matching the others"); 
	    }
	    PullDataSource pds[] = new PullDataSource[sources.length];
	    for (int i = 0; i < pds.length; i++)
		pds[i] = (PullDataSource)sources[i];
	    return reflectMDS("com.ibm.media.protocol.MergingPullDataSource", pds);
	}

	if (sources[0] instanceof PushDataSource) {
	    for (int i = 1; i < sources.length; i ++) {
		if (!(sources[i] instanceof PushDataSource))
		    throw new IncompatibleSourceException("One of the sources isn't matching the others"); 
	    }
	    PushDataSource pds[] = new PushDataSource[sources.length];
	    for (int i = 0; i < pds.length; i++)
		pds[i] = (PushDataSource)sources[i];
	    return reflectMDS("com.ibm.media.protocol.MergingPushDataSource",pds);
	}

	if (sources[0] instanceof PullBufferDataSource) {
	    for (int i = 1; i < sources.length; i ++) {
		if (!(sources[i] instanceof PullBufferDataSource))
		    throw new IncompatibleSourceException("One of the sources isn't matching the others"); 
	    }
	    PullBufferDataSource pds[] = new PullBufferDataSource[sources.length];
	    for (int i = 0; i < pds.length; i++)
		pds[i] = (PullBufferDataSource)sources[i];
	    return reflectMDS("com.ibm.media.protocol.MergingPullBufferDataSource",pds);
	}
	
	if (sources[0] instanceof PushBufferDataSource) {
	    boolean anyCapture = false;
	    for (int i = 1; i < sources.length; i ++) {
		if (!(sources[i] instanceof PushBufferDataSource))
		    throw new IncompatibleSourceException("One of the sources isn't matching the others");
		if (sources[i] instanceof CaptureDevice)
		    anyCapture = true;
	    }
	    PushBufferDataSource pds[] = new PushBufferDataSource[sources.length];
	    for (int i = 0; i < pds.length; i++)
		pds[i] = (PushBufferDataSource)sources[i];
	    if (anyCapture)
		return reflectMDS("com.ibm.media.protocol.MergingCDPushBDS",pds);
	    else
		return reflectMDS("com.ibm.media.protocol.MergingPushBufferDataSource",pds);
	}
	
	return null;
    
public static javax.media.PlayercreatePlayer(java.net.URL sourceURL)
Create a Player for the specified media. This creates a MediaLocator from the URL and then calls createPlayer.

param
sourceURL The URL that describes the media data.
return
A new Player.
exception
NoPlayerException Thrown if no Player can be found.
exception
IOException Thrown if there was a problem connecting with the source.

	return createPlayer(new MediaLocator(sourceURL));
    
public static javax.media.PlayercreatePlayer(javax.media.MediaLocator sourceLocator)
Create a Player for the specified media.

The algorithm for creating a Player from a MediaLocator is:

  1. Get the protocol from the MediaLocator.
  2. Get a list of DataSource classes that support the protocol, using the protocol package-prefix-list.
  3. For each source class in the list:
    1. Instantiate a new DataSource,
    2. Call the connect method to connect the source.
    3. Get the media content-type-name (using getContentType) from the source.
    4. Get a list of MediaHandler classes that support the media-content-type-name, using the content package-prefix-list.
    5. For each MediaHandler class in the list:
      1. Instantiate a new MediaHandler.
      2. Attach the source to the MediaHandler by calling MediaHandler.setSource.
      3. If there are no failures, determine the type of the MediaHandler; otherwise try the next MediaHandler in the list.
      4. If the MediaHandler is a Player, return the new Player.
      5. If the MediaHandler is a MediaProxy, obtain a new DataSource from the MediaProxy, obtain the list of MediaHandlers that support the new DataSource, and continue searching the new list.
    6. If no MediaHandler is found for this source, try the next source in the list.
  4. If no Player is found after trying all of the sources, reuse the source list.
    This time, for each source class in the list:
    1. Instantiate the source.
    2. Call the connect method to connect to the source.
    3. Use the content package-prefix-list to create a list of MediaHandler classes that support the "unknown" content-type-name.
    4. For each MediaHandler class in the list, search for a Player as in the previous search.
      1. If no Player is found after trying all of the sources, a NoPlayerException is thrown.

    param
    sourceLocator A MediaLocator that describes the media content.
    return
    A Player for the media described by the source.
    exception
    NoPlayerException Thrown if no Player can be found.
    exception
    IOException Thrown if there was a problem connecting with the source.

    
            Player newPlayer = null;
    	Hashtable sources = new Hashtable(10); // A repository of connected sources.
    	    
    	boolean needPluginPlayer = ((Boolean)Manager.getHint(PLUGIN_PLAYER)).booleanValue();
    
    	// For RTP, the "non-plugin" player
    	// (com.sun.media.content.rtp.Handler) actually supports plugin.
    	String protocol = sourceLocator.getProtocol();
    	if (protocol != null && 
    	    (protocol.equalsIgnoreCase("rtp") || protocol.equalsIgnoreCase("rtsp")))
    	    needPluginPlayer = false;
    
    	try {
    	    newPlayer = createPlayerForContent(sourceLocator, needPluginPlayer, sources);
    	} catch (NoPlayerException e) {
    	    // ... and if that doesn't work, try finding
    	    // a player for the UNKNOWN_CONTENT_NAME.
    
    	    if (needPluginPlayer)
    		throw e;
    	    newPlayer = createPlayerForContent(sourceLocator, true, sources);
    	}
    
    	// Disconnect the unsed sources
    	if (sources.size() != 0) {
    	    Enumeration enum = sources.elements();
    	    while (enum.hasMoreElements()) {
    		DataSource ds = (DataSource)enum.nextElement();
    		ds.disconnect();
    	    }
    	}
    
    	return newPlayer;
        
public static javax.media.PlayercreatePlayer(javax.media.protocol.DataSource source)
Create a Player for the DataSource.

The algorithm for creating a Player from a DataSource is:

  1. Get the media content-type-name from the source by calling getContentType.
  2. Use the content package-prefix-list to get a list of Player classes that support the media content-type name.
  3. For each Player class in the list:
    1. Instantiate a new Player.
    2. Attach the source to the Player by calling setSource on the Player.
    3. If there are no failures, return the new Player; otherwise, try the next Player in the list.
  4. If no Player is found for this source:
    1. Use the content package-prefix-list to create a list of Player classes that support the "unknown" content-type-name.
    2. For each Player class in the list:
      1. Instantiate a new Player.
      2. Attach the source to the Player by calling setSource on the Player.
      3. If there are no failures, return the new Player; otherwise, try the next Player in the list.
  5. If no Player can be created, a NoPlayerException is thrown.

param
DataSource The DataSource that describes the media content.
return
A new Player.
exception
NoPlayerException Thrown if a Player can't be created.
exception
IOException Thrown if there was a problem connecting with the source.


	Player newPlayer;
	boolean needPluginPlayer = ((Boolean)Manager.getHint(PLUGIN_PLAYER)).booleanValue();
	String contentType = source.getContentType();

	// For RTP, the "non-plugin" player
	// (com.sun.media.content.rtp.Handler) actually supports plugin.
	if (contentType != null && 
	    (contentType.equalsIgnoreCase("rtp") || contentType.equalsIgnoreCase("rtsp")))
	    needPluginPlayer = false;

	try {
	    // First try and create one using the source
	    // as the content identifier ...
	    if (needPluginPlayer)
		contentType = UNKNOWN_CONTENT_NAME;
	    newPlayer = createPlayerForSource(source, contentType, null);
	} catch( NoPlayerException e) {
	    // ... if that doesn't work use the unknown-content type.
	    if (needPluginPlayer)
		throw e;
	    newPlayer = createPlayerForSource(source, UNKNOWN_CONTENT_NAME, null);
	}

	return newPlayer;
    
static javax.media.PlayercreatePlayerForContent(javax.media.MediaLocator sourceLocator, boolean useUnknownContent, java.util.Hashtable sources)
Create a player for the MediaLocator.

If useUnknownContent is true, a Player for content-type UNKNOWN_CONTENT_NAME is created; otherwise, the DataSource determines the content-type with the getContentType method.

param
sourceLocator Used to determine the protocol that the DataSource will use.
param
useKnownContent Used to determine the content type used to find a Player.
returns
A new Player.
exception
NoPlayerException Thrown if no Player can be found.
exception
IOException Thrown if there was a problem connecting with the source.


	Player newPlayer = null;
	boolean sourceUsed[] = new boolean[1];
	sourceUsed[0] = false;	// A pass-by-referenced boolean to indicate
				// if the data source has been used.
				// If so, it need to be disconnected.
	    
	// For each DataSource that implements the protocol
        // that's specified in the source ...

	Enumeration protoList =
	    getDataSourceList(sourceLocator.getProtocol()).elements();
	while(protoList.hasMoreElements()) {
	    
	    String protoClassName = (String)protoList.nextElement();

	    DataSource source = null; // 
	    try {

		// Look into the registry to see if that DataSource
		// has already been created.
		if ((source = (DataSource)sources.get(protoClassName)) == null) {

		    // ... Try an instance a DataSource ....
		    Class protoClass = getClassForName(protoClassName);
		    source = (DataSource)protoClass.newInstance();

		    // ... and get it connected ....
		    source.setLocator(sourceLocator);
		    source.connect();
		} else
		    sources.remove(protoClassName);

		// ... o.k. we've found one, so now try and get
		// a Player for it.
		try {
		    if( useUnknownContent) {
			// Either use the default content type ...
			newPlayer = createPlayerForSource(source, 
					UNKNOWN_CONTENT_NAME, sourceUsed);
		    } else {
			// ... or let the source specify the content type.
			newPlayer =
			    createPlayerForSource(source, 
					source.getContentType(), sourceUsed);
		    }

		    // If we got one we're done.
		    break;
		    
		} catch (NoPlayerException e) {
		    // Go try another one.
		    newPlayer = null;
		}
		
		// No luck so try another source.
		if (sourceUsed[0])
		    source.disconnect();
		else
		    sources.put(protoClassName, source);
		
	    } catch (ClassNotFoundException e) {
		// try another data source.
		source = null;
	    } catch (InstantiationException e) {
		// try another one.
		source = null;
	    } catch (IllegalAccessException e) {
		// try another one.
		source = null;
	    } catch (Exception e) {
		source = null;
		String err = "Error instantiating class: " + protoClassName + " : " + e;
		Log.error(e);
		throw new NoPlayerException(err);
	    } catch (Error e) {
		source = null;
		String err = "Error instantiating class: " + protoClassName + " : " + e;
		Log.error(e);
		throw new NoPlayerException(err);
	    }
	}

// TEMPORARILY COMMENTED OUT URLDataSource: 1/15/99
	// If we don't have a Player yet, then try and create a Player
	// from the URL data source.
// 	DataSource source = null;
// 	sourceUsed[0] = false;
// 	if( newPlayer == null) {
// 	    try {

// 		if ((source = (DataSource)sources.get("javax.media.URLDataSource")) == null) {
// 		    source = new URLDataSource(sourceLocator.getURL());
// 		    source.connect();
// 		} else
// 		    sources.remove("javax.media.URLDataSource");

// 		// Got the data source so attach it to
// 		// a player.
// 		if( useUnknownContent) {
// 		    // Either use the default content type ...
// 		    newPlayer = createPlayerForSource(source, 
// 					UNKNOWN_CONTENT_NAME, sourceUsed);
// 		} else {
// 		    // ... or let the source specify the content type.
// 		    newPlayer =
// 			createPlayerForSource(source, 
// 					source.getContentType(), sourceUsed);
// 		}

// 	    } catch(MalformedURLException me) {
// 		// Can't get a URL so we're done.
// 		source = null;
// 	    } finally {
// 		if (source != null) {
// 		    if (sourceUsed[0])
// 			source.disconnect();
// 		    else
// 	        	sources.put("javax.media.URLDataSource", source);
// 		}
// 	    }
// 	}

	if( newPlayer == null)
	    throw new NoPlayerException("Cannot find a Player for :" + sourceLocator);

	return newPlayer;
    
static javax.media.PlayercreatePlayerForSource(javax.media.protocol.DataSource source, java.lang.String contentTypeName, boolean[] sourceUsed)
Create a Player for a particular content type using the source.

param
source The source of media for the Player.
param
contentTypeName The type of content the Player should handle.
return
A new Player.
exception
NoPlayerException Thrown if no Player can be found for the source and content-type.
exception
IOException Thrown if there was a problem connecting with the source.


	Player newPlayer = null;
	if (sourceUsed != null) sourceUsed[0] = true;

	// Try every handler we can find for this content type.
	Enumeration playerList =
	    getHandlerClassList(contentTypeName).elements();

	MediaHandler mHandler;
	DataSource newSource = null;
	while(playerList.hasMoreElements()) {
	    String handlerClassName = (String)playerList.nextElement();

	    try {
		
		// ... try and instance the handler ...
		Class handlerClass = getClassForName(handlerClassName);
		mHandler = (MediaHandler)handlerClass.newInstance();
		// ... set the DataSource on it ...
		mHandler.setSource(source);

		// if this is a Player then we're done.
		if( mHandler instanceof Player) {
		    newPlayer = (Player)mHandler;
		    break;
		}

		// Otherwise it must be a proxy.
		// Get a new data source, and content type  ...
		MediaProxy mProxy = (MediaProxy)mHandler;
		newSource = mProxy.getDataSource();
		String newContentType = newSource.getContentType();
		// .. recurse to try and create a Player with it.
		try{
		    newPlayer =
			createPlayerForSource(newSource,newContentType, null);
		}catch (NoPlayerException e){
		    newPlayer = createPlayerForSource(newSource,
						      UNKNOWN_CONTENT_NAME,
						      null);
		    if (newPlayer != null)
			break;
		}
	    
		
	    } catch (ClassNotFoundException e) {
		// Couldn't find the handler so try another.
		newPlayer = null;
		if (sourceUsed != null) sourceUsed[0] = false;
	    } catch (InstantiationException e) {
		// Can't instance the handler so try another.
		newPlayer = null;
		if (sourceUsed != null) sourceUsed[0] = false;
	    } catch (IllegalAccessException e) {
		// Can't get at the handler so try another.
		newPlayer = null;
		if (sourceUsed != null) sourceUsed[0] = false;
	    } catch (IncompatibleSourceException e) {
		// The handler didn't know what to
		// do with the DataSource so try another handler.
		newPlayer = null;
	    } catch (NoDataSourceException e) {
		// Proxy failed to produce a new data source
		// see if there are other proxies out there.
		newPlayer = null;
	    } catch (Exception e) {
		newPlayer = null;
		String err = "Error instantiating class: " + handlerClassName + " : " + e;
		throw new NoPlayerException(err);
	    } catch (Error e) {
		String err = "Error instantiating class: " + handlerClassName + " : " + e;
 		Log.error(e);
		throw new NoPlayerException(err);
	    }

	}

	if( newPlayer == null) {
	    throw new NoPlayerException("Cannot find a Player for: " + source);
	}

	Log.comment("Player created: " + newPlayer);
	Log.comment("  using DataSource: " + source + "\n");

	return newPlayer;
    
public static javax.media.ProcessorcreateProcessor(javax.media.MediaLocator sourceLocator)
Create a Processor for the specified media.

The algorithm is similar to that for creating a Player from a MediaLocator

param
sourceLocator A MediaLocator that describes the media content.
return
A Processor for the media described by the source.
exception
NoProcessorException Thrown if no Processor can be found.
exception
IOException Thrown if there was a problem connecting with the source.


        Processor newProcessor = null;
	Hashtable sources = new Hashtable(10); // A repository of connected sources.
	    
	try {
	    newProcessor = createProcessorForContent(sourceLocator, 
					false, sources);
	} catch (NoProcessorException e) {
	    // ... and if that doesn't work, try finding
	    // a player for the UNKNOWN_CONTENT_NAME.
	    newProcessor = createProcessorForContent(sourceLocator, 
					true, sources);
	}

	// Disconnect the unsed sources
	if (sources.size() != 0) {
	    Enumeration enum = sources.elements();
	    while (enum.hasMoreElements()) {
		DataSource ds = (DataSource)enum.nextElement();
		ds.disconnect();
	    }
	}

	return newProcessor;
    
public static javax.media.ProcessorcreateProcessor(javax.media.protocol.DataSource source)
Create a Processor for the DataSource.

The algorithm for creating a Processor is similar to creating a Player from a DataSource.

param
DataSource The DataSource that describes the media content.
return
A new Processor.
exception
NoProcessorException Thrown if a Processor can't be created.
exception
IOException Thrown if there was a problem connecting with the source.


	Processor newProcessor;
	try {
	    // First try and create one using the source
	    // as the content identifier ...
	    newProcessor = createProcessorForSource(source, source.getContentType(), null);
	} catch( NoProcessorException e) {
	    // ... if that doesn't work use the unknown-content type.
	    newProcessor = createProcessorForSource(source, UNKNOWN_CONTENT_NAME, null);
	}

	return newProcessor;
    
public static javax.media.ProcessorcreateProcessor(java.net.URL sourceURL)
Create a Processor for the specified media.

The algorithm is similar to that for creating a Player from a URL

param
sourceURL A URL that describes the media content.
return
A Processor for the media described by the source.
exception
NoProcessorException Thrown if no Processor can be found.
exception
IOException Thrown if there was a problem connecting with the source.

	return createProcessor(new MediaLocator(sourceURL));
    
static javax.media.ProcessorcreateProcessorForContent(javax.media.MediaLocator sourceLocator, boolean useUnknownContent, java.util.Hashtable sources)
Create a player for the MediaLocator.

If useUnknownContent is true, a Processor for content-type UNKNOWN_CONTENT_NAME is created; otherwise, the DataSource determines the content-type with the getContentType method.

param
sourceLocator Used to determine the protocol that the DataSource will use.
param
useKnownContent Used to determine the content type used to find a Processor.
returns
A new Processor.
exception
NoProcessorException Thrown if no Processor can be found.
exception
IOException Thrown if there was a problem connecting with the source.


	Processor newProcessor = null;
	boolean sourceUsed[] = new boolean[1];
	sourceUsed[0] = false;	// A pass-by-referenced boolean to indicate
				// if the data source has been used.
				// If so, it need to be disconnected.
	    
	// For each DataSource that implements the protocol
        // that's specified in the source ...
	Enumeration protoList =
	    getDataSourceList(sourceLocator.getProtocol()).elements();
	while(protoList.hasMoreElements()) {
	    
	    String protoClassName = (String)protoList.nextElement();
	    DataSource source = null;
	    try {

		// Look into the registry to see if that DataSource
		// has already been created.
		if ((source = (DataSource)sources.get(protoClassName)) == null) {

		    // ... Try an instance a DataSource ....
		    Class protoClass = getClassForName(protoClassName);
		    source = (DataSource)protoClass.newInstance();

		    // ... and get it connected ....
		    source.setLocator(sourceLocator);
		    source.connect();
		} else
		    sources.remove(protoClassName);

		// ... o.k. we've found one, so now try and get
		// a Processor for it.
		try {
		    if( useUnknownContent) {
			// Either use the default content type ...
			newProcessor = createProcessorForSource(source, 
					UNKNOWN_CONTENT_NAME, sourceUsed);
		    } else {
			// ... or let the source specify the content type.
			newProcessor =
			    createProcessorForSource(source, 
					source.getContentType(), sourceUsed);
		    }

		    // If we got one we're done.
		    break;
		    
		} catch (NoProcessorException e) {
		    // Go try another one.
		    newProcessor = null;
		}
		
		// No luck so try another source.
		if (sourceUsed[0])
		    source.disconnect();
		else
		    sources.put(protoClassName, source);
		
	    } catch (ClassNotFoundException e) {
		// try another data source.
		source = null;
	    } catch (InstantiationException e) {
		// try another one.
		source = null;
	    } catch (IllegalAccessException e) {
		// try another one.
		source = null;
	    } catch (Exception e) {
		String err = "Error instantiating class: " + protoClassName + " : " + e;
		Log.error(e);
		throw new NoProcessorException(err);
	    } catch (Error e) {
		String err = "Error instantiating class: " + protoClassName + " : " + e;
		Log.error(e);
		throw new NoProcessorException(err);
	    }
	}

	// TEMPORARILY COMMENTED OUT URLDataSource: 1/15/99
	// If we don't have a Processor yet, then try and create a Processor
	// from the URL data source.
// 	DataSource source = null;
// 	sourceUsed[0] = false;
// 	if( newProcessor == null) {
// 	    try {

// 		if ((source = (DataSource)sources.get("javax.media.URLDataSource")) == null) {
// 		    source = new URLDataSource(sourceLocator.getURL());
// 		    source.connect();
// 		} else
// 		    sources.remove("javax.media.URLDataSource");

// 		// Got the data source so attach it to
// 		// a player.
// 		if( useUnknownContent) {
// 		    // Either use the default content type ...
// 		    newProcessor = createProcessorForSource(source, 
// 					UNKNOWN_CONTENT_NAME, sourceUsed);
// 		} else {
// 		    // ... or let the source specify the content type.
// 		    newProcessor =
// 			createProcessorForSource(source, 
// 					source.getContentType(), sourceUsed);
// 		}

// 	    } catch(MalformedURLException me) {
// 		// Can't get a URL so we're done.
// 		source = null;
// 	    } finally {
// 		if (source != null) {
// 		    if (sourceUsed[0])
// 			source.disconnect();
// 		    else
// 	        	sources.put("javax.media.URLDataSource", source);
// 		}
// 	    }
// 	}

	if( newProcessor == null)
	    throw new NoProcessorException("Cannot find a Processor for: " + sourceLocator);

	return newProcessor;
    
static javax.media.ProcessorcreateProcessorForSource(javax.media.protocol.DataSource source, java.lang.String contentTypeName, boolean[] sourceUsed)
Create a Processor for a particular content type using the source.

param
source The source of media for the Processor.
param
contentTypeName The type of content the Processor should handle.
return
A new Processor.
exception
NoProcessorException Thrown if no Processor can be found for the source and content-type.
exception
IOException Thrown if there was a problem connecting with the source.


	Processor newProcessor = null;
	if (sourceUsed != null) sourceUsed[0] = true;

	// Try every handler we can find for this content type.
	Enumeration playerList =
	    getProcessorClassList(contentTypeName).elements();

	MediaHandler mHandler;
	DataSource newSource = null;
	while(playerList.hasMoreElements()) {
	    String handlerClassName = (String)playerList.nextElement();

	    try {
		
		// ... try and instance the handler ...
		Class handlerClass = getClassForName(handlerClassName);
		mHandler = (MediaHandler)handlerClass.newInstance();
		
		// ... set the DataSource on it ...
		mHandler.setSource(source);

		// if this is a Processor then we're done.
		if( mHandler instanceof Processor) {
		    newProcessor = (Processor)mHandler;
		    break;
		}

		// Otherwise it must be a proxy.
		// Get a new data source, and content type  ...
		MediaProxy mProxy = (MediaProxy)mHandler;
		newSource = mProxy.getDataSource();
		String newContentType = newSource.getContentType();

		// .. recurse to try and create a Player with it.
		try{
		    newProcessor =
			createProcessorForSource(newSource,newContentType, null);
		}catch (NoProcessorException e){
		    newProcessor = createProcessorForSource(newSource,
							 UNKNOWN_CONTENT_NAME,
							 null);
		    if (newProcessor != null)
			break;
		}
		
	    } catch (ClassNotFoundException e) {
		// Couldn't find the handler so try another.
		newProcessor = null;
		if (sourceUsed != null) sourceUsed[0] = false;
	    } catch (InstantiationException e) {
		// Can't instance the handler so try another.
		newProcessor = null;
		if (sourceUsed != null) sourceUsed[0] = false;
	    } catch (IllegalAccessException e) {
		// Can't get at the handler so try another.
		newProcessor = null;
		if (sourceUsed != null) sourceUsed[0] = false;
	    } catch (IncompatibleSourceException e) {
		// The handler didn't know what to
		// do with the DataSource so try another handler.
		newProcessor = null;
	    } catch (NoDataSourceException e) {
		// Proxy failed to produce a new data source
		// see if there are other proxies out there.
		newProcessor = null;
	    } catch (Exception e) {
		newProcessor = null;
		String err = "Error instantiating class: " + handlerClassName + " : " + e;
		Log.error(e);
		throw new NoProcessorException(err);
	    } catch (Error e) {
		newProcessor = null;
		String err = "Error instantiating class: " + handlerClassName + " : " + e;
		Log.error(e);
		throw new NoProcessorException(err);
	    }

	}

	if( newProcessor == null) {
	    throw new NoProcessorException("Cannot find a Processor for: " + source);
	}

	Log.comment("Processor created: " + newProcessor);
	Log.comment("  using DataSource: " + source + "\n");

	return newProcessor;
    
public static javax.media.PlayercreateRealizedPlayer(java.net.URL sourceURL)
Create a Realized Player for the specified media.

This is a blocking method that creates a Player, calls realize on it and returns only after the Player has been Realized. Realizing a Player could be a time consuming operation and one should use caution when using this method as it could block the thread for several seconds.

param
ml The MediaLocator that describes the source of the media.
return
A new Player that is in the Realized state.
exception
NoPlayerException Thrown if a Player can't be created.
exception
IOException Thrown if there was a problem connecting with the source.
exception
CannotRealizeException Thrown if there was a problem realizing the Player.

	Player p = createPlayer(sourceURL);
	blockingCall(p, Controller.Realized);
	return p;
    
public static javax.media.PlayercreateRealizedPlayer(javax.media.MediaLocator ml)
Create a Realized Player for the specified media.

This is a blocking method that creates a Player, calls realize on it and returns only after the Player has been Realized. Realizing a Player could be a time consuming operation and one should use caution when using this method as it could block the thread for several seconds.

param
ml The MediaLocator that describes the source of the media.
return
A new Player that is in the Realized state.
exception
NoPlayerException Thrown if a Player can't be created.
exception
IOException Thrown if there was a problem connecting with the source.
exception
CannotRealizeException Thrown if there was a problem realizing the Player.

	Player p = createPlayer(ml);
	blockingCall(p, Controller.Realized);
	return p;
    
public static javax.media.PlayercreateRealizedPlayer(javax.media.protocol.DataSource source)
Create a Realized Player for the specified source.

This is a blocking method that creates a Player, calls realize on it and returns only after the Player has been Realized. Realizing a Player could be a time consuming operation and one should use caution when using this method as it could block the thread for several seconds.

param
source The DataSource that describes the media content.
return
A new Player that is in the Realized state.
exception
NoPlayerException Thrown if a Player can't be created.
exception
IOException Thrown if there was a problem connecting with the source.
exception
CannotRealizeException Thrown if there was a problem realizing the Player.

	Player p = createPlayer(source);
	blockingCall(p, Controller.Realized);
	return p;
    
public static javax.media.ProcessorcreateRealizedProcessor(javax.media.ProcessorModel model)
Create a Realized Processor for the specified ProcessorModel.

This method accepts a ProcessorModel that describes the required input and/or output format of the media data. It is a blocking method and returns only after the Processor reaches the Realized state.

see
ProcessorModel
param
model The ProcessorModel that describes the input and output media
return
A new Processor that is in the Realized state.
exception
NoProcessorException Thrown if a Processor can't be created.
exception
IOException Thrown if there was a problem connecting with the source.
exception
CannotRealizeException Thrown if there was a problem realizing the Player.


	DataSource ds = null;
	MediaLocator ml = null;
	Processor processor = null;
	ContentDescriptor [] cds;
	ContentDescriptor rcd;
	boolean matched = false;
	Format [] reqFormats = null;
	Format    prefFormat;
	int    reqNumTracks = -1;
	int [] procToReqMap;
	TrackControl [] procTracks;
	int    i, j, k;
	int    nTracksEnabled = 0;
	boolean [] enabled;
	
	if (model == null)
	    throw new NoProcessorException("null ProcessorModel");

	// Figure out if we should use a datasource or a media locator as the
	// source. DataSource takes precedence over MediaLocator.
	ds = model.getInputDataSource();
	if (ds != null) {
	    processor = Manager.createProcessor(ds);
	} else if ((ml = model.getInputLocator()) != null) {
	    processor = Manager.createProcessor(ml);
	} else {
	    // Capture sources...
	    int nDevices = getNTypesOfCaptureDevices();
	    Vector dataSourceList = new Vector(1);
	    reqNumTracks = model.getTrackCount(nDevices);
	    reqFormats = new Format[reqNumTracks];
	    for (i = 0; i < reqNumTracks; i++) {
		reqFormats[i] = model.getOutputTrackFormat(i);
		// Look for a direct match
		Vector deviceList = CaptureDeviceManager.getDeviceList(reqFormats[i]);
		if (deviceList == null || deviceList.size() == 0) {
		    // No direct match. Find a similar device and hope to transcode
		    if (reqFormats[i] instanceof AudioFormat)
			deviceList = CaptureDeviceManager.getDeviceList(
							      new AudioFormat(null));
		    else if (reqFormats[i] instanceof VideoFormat)
			deviceList = CaptureDeviceManager.getDeviceList(
							      new VideoFormat(null));
		}

		if (deviceList.size() != 0) {
		    CaptureDeviceInfo cdi = (CaptureDeviceInfo) deviceList.elementAt(0);
		    if (cdi != null && cdi.getLocator() != null) {
			try {
			    DataSource crds = Manager.createDataSource(cdi.getLocator());
			    if (crds instanceof CaptureDevice) {
				// Set the format
				FormatControl [] fc = ((CaptureDevice)crds).getFormatControls();
				if (fc.length > 0) {
				    Format [] supported = fc[0].getSupportedFormats();
				    if (supported.length > 0) {
					for (int f = 0; f < supported.length; f++) {
					    if (supported[f].matches(reqFormats[i])) {
						Format intersect =
						    supported[f].intersects(reqFormats[i]);
						if (intersect != null) {
						    if (fc[0].setFormat(intersect) != null)
							break;
						}
					    }
					}
				    }
				}
			    }
			    // ds.connect(); ???
			    dataSourceList.addElement(crds);
			} catch (IOException ioe) {
			} catch (NoDataSourceException ndse) {
			}
		    }
		}
	    }
	    
	    if (dataSourceList.size() == 0) {
		throw new NoProcessorException("No suitable capture devices found!");
	    } else if (dataSourceList.size() > 1) {
		// Merge the datasources
		DataSource [] dataSourceArray = new DataSource[dataSourceList.size()];
		for (k = 0; k < dataSourceList.size(); k++)
		    dataSourceArray[k] = (DataSource) dataSourceList.elementAt(k);
		try {
		    ds = Manager.createMergingDataSource(dataSourceArray);
		} catch (IncompatibleSourceException ise) {
		    throw new NoProcessorException("Couldn't merge capture devices");
		}
	    } else
		ds = (DataSource) dataSourceList.elementAt(0);
	    processor = Manager.createProcessor(ds);
	}

	if (processor == null)
	    throw new NoProcessorException("Couldn't create Processor for source");

	// Configure the processor
	blockingCall(processor, Processor.Configured);

	// Content descriptor stuff
	rcd = model.getContentDescriptor();
	if (rcd == null) {
	    processor.setContentDescriptor(null);
	} else {
	    cds = processor.getSupportedContentDescriptors();
	    if (cds == null || cds.length == 0)
		throw new NoProcessorException("Processor doesn't support output");
	    
	    for (i = 0; i < cds.length; i++) {
		if (rcd.matches(cds[i])) {
		    if (processor.setContentDescriptor(cds[i]) != null) {
			matched = true;
			break;
		    } 
		}
	    }
	    if (!matched)
		throw new NoProcessorException("Processor doesn't support requested " +
					       "output ContentDescriptor");
	    
	}

	procTracks = processor.getTrackControls();
	if (procTracks != null && procTracks.length > 0) {
	    // Format stuff
	    int nValidTracks = 0;
	    for (i = 0; i < procTracks.length; i++) {
		if (procTracks[i].isEnabled())
		    nValidTracks++;
	    }
	    if (reqNumTracks == -1)
		reqNumTracks = model.getTrackCount(nValidTracks);
	    if (reqNumTracks > 0) {
		if (reqFormats == null) 
		    reqFormats = new Format[reqNumTracks];
		procToReqMap = new int[reqNumTracks];     // Whats the proc's trackNo for a
						      // requested track no.
		for (i = 0; i < reqNumTracks; i++) {
		    if (reqFormats[i] == null)
			reqFormats[i] = model.getOutputTrackFormat(i);
		    procToReqMap[i] = -1;
		}
		
		enabled = new boolean[procTracks.length];
		// First try the default track formats.
		for (i = 0; i < procTracks.length; i++) {
		    enabled[i] = false;
		    if (!procTracks[i].isEnabled())
			continue;
		    prefFormat = procTracks[i].getFormat();
		    for (j = 0; j < reqNumTracks; j++) {
			if ( procToReqMap[j] == -1 &&
			     ( reqFormats[j] == null ||
			       prefFormat.matches(reqFormats[j]) ) ) {
			    
			    if (model.isFormatAcceptable(j, prefFormat)) {
				procToReqMap[j] = i;
				enabled[i] = true;
				nTracksEnabled++;
				//procTracks[i].setFormat(prefFormat); // no need to do this
				break;
			    }
			}
		    }
		}
		
		for (i = 0; i < procTracks.length && nTracksEnabled < reqNumTracks; i++) {
		    boolean used = false;
		    Format [] suppFormats;
		    // If not enabled by processor, its not to be used
		    if (!procTracks[i].isEnabled())
			continue;
		    // Check if its already been matched with one of the requested
		    for (j = 0; j < reqNumTracks; j++)
			if (procToReqMap[j] == i)
			    used = true;
		    if (used)
			continue;
		    
		    // Get all the supported formats for this track (transcode)
		    suppFormats = procTracks[i].getSupportedFormats();
		    if (suppFormats == null || suppFormats.length == 0)
			continue;
		    
		    matched = false;
		    for (k = 0; k < suppFormats.length && !matched; k++) {
			prefFormat = suppFormats[k];
			for (j = 0; j < reqNumTracks && !matched; j++) {
			    //System.err.println("trying " + prefFormat + " && " + reqFormats[j]);   
			    if ( procToReqMap[j] == -1 &&
				 ( reqFormats[j] == null ||
				   prefFormat.matches(reqFormats[j]) ) ) {
				
				if (model.isFormatAcceptable(j, prefFormat)) {
				    if (procTracks[i].setFormat(prefFormat) != null) {
					procToReqMap[j] = i;
					enabled[i] = true;
					nTracksEnabled++;
					matched = true;
					break;
				    }
				}
			    }
			    
			}
		    }
		}
		
		if (nTracksEnabled < reqNumTracks) {
		    // What should we do if all requested tracks are not satisfied?
		    // Is failing the right thing to do
		    throw new CannotRealizeException("Unable to provide all " +
						     "requested tracks");
		}
	    }
	}

	blockingCall(processor, Controller.Realized);

	return processor;
    
public static java.lang.StringgetCacheDirectory()
Retrieve the directory that's used for playback caching.

return
the directory that's used for playback caching, null if the directory is not specified.

	String cacheDir;
	Object cdir = com.sun.media.util.Registry.get("secure.cacheDir");

	if ( (cdir != null) && (cdir instanceof String) ) {
	    cacheDir = (String) cdir;;

	    if (cacheDir.indexOf(fileSeparator) == -1) {
		if (fileSeparator.equals("/")) {
		    cacheDir = "/tmp";
		} else if (fileSeparator.equals("\\")) {
		    cacheDir = "C:" + fileSeparator + "temp";
		} else {
		    cacheDir = null;
		}
	    }
	    return cacheDir;
	}

	if (fileSeparator.equals("/")) {
	    cacheDir = "/tmp";
	} else if (fileSeparator.equals("\\")) {
	    cacheDir = "C:" + fileSeparator + "temp";
	} else {
	    cacheDir = null;
	}
	return cacheDir;
    
static java.lang.ClassgetClassForName(java.lang.String className)

	/**
	 *  Note: if we don't want this functionality
	 *  just replace it with Class.forName(className)
	 */

	try {
	    return Class.forName(className);
	} catch (Exception e) {
	    if (!checkIfJDK12()) {
		throw new ClassNotFoundException(e.getMessage());
	    }
	} catch (Error e) {
	    if (!checkIfJDK12()) {
		throw e;
	    }
	}

	/**
	 *  In jdk1.2 application, when you have jmf.jar in the ext directory and
	 *  you want to access a class that is not in jmf.jar but is in the CLASSPATH,
	 *  you have to load it using the the system class loader.
	 */
	try {
	    return (Class) forName3ArgsM.invoke(Class.class, new Object[] {
		className, new Boolean(true), systemClassLoader});
	} catch (Throwable e) {
	}

	/**
	 *  In jdk1.2 applet, when you have jmf.jar in the ext directory and
	 *  you want to access a class that is not in jmf.jar but applet codebase,
	 *  you have to load it using the the context class loader.
	 */
	try {
	    // TODO: may need to invoke RuntimePermission("getClassLoader") privilege
	    ClassLoader contextClassLoader =
		(ClassLoader) getContextClassLoaderM.invoke(Thread.currentThread(), null);
	    return (Class) forName3ArgsM.invoke(Class.class, new Object[] {
		className, new Boolean(true), contextClassLoader});
	} catch (Exception e) {
	    throw new ClassNotFoundException(e.getMessage());
	} catch (Error e) {
	    throw e;
	}
    
static java.util.VectorgetContentPrefixList()

	return (Vector)PackageManager.getContentPrefixList().clone();
    
public static java.util.VectorgetDataSourceList(java.lang.String protocolName)
Build a list of DataSource class names from the protocol prefix-list and a protocol name.

The first name in the list will always be:

media.protocol.<protocol>.DataSource

Each additional name looks like:

<protocol-prefix>.media.protocol.<protocol>.DataSource
for every <protocol-prefix> in the protocol-prefix-list.

param
protocol The name of the protocol the source must support.
return
A vector of strings, where each string is a Player class-name.


	// The first element is the name of the protocol handler ...
	String sourceName =
	    "media.protocol." + protocolName + ".DataSource";

	return buildClassList(getProtocolPrefixList(), sourceName);
    
public static java.util.VectorgetHandlerClassList(java.lang.String contentName)
Build a list of Player Handler classes from the content-prefix-list and a content name.

The first name in the list will always be:

media.content.<contentType>.Handler

Each additional name looks like:

<content-prefix>.media.content.<contentName>.Player
for every <content-prefix> in the content-prefix-list.

param
contentName The content type to use in the class name.
return
A vector of strings where each one is a Player class-name.


	// players are found by content type ....
	String handlerName = "media.content." + 
			ContentDescriptor.mimeTypeToPackageName(contentName) + 
			".Handler";

	// ... build a list of classes using the content-prefix-list.
	return buildClassList(getContentPrefixList(), handlerName);
    
public static java.lang.ObjectgetHint(int hint)
Retrieve the value of a hint set.

param
hint The name of the hint.
return
The value of the hint.
see
#MAX_SECURITY
see
#CACHING
see
#LIGHTWEIGHT_RENDERER
see
#PLUGIN_PLAYER

	if ( (hint >= 1) && (hint <= numberOfHints) ) {
	    return hintTable.get(new Integer(hint));
	} else {
	    return null;
	}
    
private static intgetNTypesOfCaptureDevices()

	int nDevices = 0;
	Vector audioDevs = CaptureDeviceManager.getDeviceList(new AudioFormat(null));
	Vector videoDevs = CaptureDeviceManager.getDeviceList(new VideoFormat(null));
	if (audioDevs != null && audioDevs.size() > 0)
	    nDevices++;
	if (videoDevs != null && videoDevs.size() > 0)
	    nDevices++;
	return nDevices;
    
public static java.util.VectorgetProcessorClassList(java.lang.String contentName)
Build a list of Processor Handler classes from the content-prefix-list and a content name.

The first name in the list will always be:

media.processor.<contentType>.Handler

Each additional name looks like:

<content-prefix>.media.processor.<contentName>.Processor
for every <content-prefix> in the content-prefix-list.

param
contentName The content type to use in the class name.
return
A vector of strings where each one is a Processor class-name.


	// players are found by content type ....
	String handlerName = "media.processor." + 
			ContentDescriptor.mimeTypeToPackageName(contentName) + 
			".Handler";

	// ... build a list of classes using the content-prefix-list.
	return buildClassList(getContentPrefixList(), handlerName);
    
static java.util.VectorgetProtocolPrefixList()

	return (Vector) PackageManager.getProtocolPrefixList().clone();
    
public static javax.media.TimeBasegetSystemTimeBase()
Get the time-base object for the system.

return
The system time base.

	if (sysTimeBase == null) {
	    sysTimeBase = new SystemTimeBase();
	}
	return sysTimeBase;
    
public static java.lang.StringgetVersion()
Returns the version string for this revision of JMF.

	return VERSION;
    
private static javax.media.protocol.DataSourcereflectDS(java.lang.String cname, javax.media.protocol.DataSource source)

	Class cls;
	Constructor cc;
	Class[] paramTypes = new Class[1];
	Object[] arg = new Object[1];

	try {
	    cls = Class.forName(cname);

	    if ( cname.indexOf("PullDataSource") >= 0) {
		paramTypes[0] = PullDataSource.class;
		arg[0] = (PullDataSource)source;
	    } else if ( cname.indexOf("PushDataSource") >= 0) {
		paramTypes[0] = PushDataSource.class;
		arg[0] = (PushDataSource)source;
	    } else if ( cname.indexOf("PullBufferDataSource") >= 0) {
		paramTypes[0] = PullBufferDataSource.class;
		arg[0] = (PullBufferDataSource)source;
	    } else if ( cname.indexOf("PushBufferDataSource") >= 0 ) {
		paramTypes[0] = PushBufferDataSource.class;
		arg[0] = (PushBufferDataSource)source;
	    }

	    cc = cls.getConstructor(paramTypes);
	    return (DataSource)(cc.newInstance(arg));
	} catch (Exception ex) {
	    // return null;
	}
	
	return null;
    
private static javax.media.protocol.DataSourcereflectMDS(java.lang.String cname, java.lang.Object pds)
Creates a cloneable DataSource. The returned DataSource implements the SourceCloneable interface and enables the creation of clones by the createClone method.
If the input DataSource implements SourceCloneable, it will be returned right away as the result. Otherwise, a "proxy" DataSource is created. It implements the SourceCloneable interface and can be used to generate other clones.
When createCloneableDataSource is called on a DataSource, the returned DataSource should be used in place of the original DataSource. Any attempt to use the original DataSource may generate unpredictable results.
The resulted cloneable DataSource can be used to generate clones. The clones generated may or may not has the same properties of the original DataSource depending on the implementation. Therefore, they should be checked against the properties required for the application. If the original DataSource is not SourceCloneable and a "proxy" DataSource is resulted, the clones generated from this "proxy" DataSource is of type PushDataSource or PushBufferDataSource depending on the type of the original DataSource. In this case, each clone pushes data at the same rate that the original DataSource is pulled or pushed.

see
SourceCloneable
param
source the DataSource to be cloned
return
a cloneable DataSource for the given source

	Class cls;
	Constructor cc;
	Class[] paramTypes = new Class[1];
	Object[] arg = new Object[1];

	try {
	    cls = Class.forName(cname);
	    paramTypes[0] = pds.getClass();
	    
	    cc = cls.getConstructor(paramTypes);

	    if ( cname.indexOf("PullDataSource") >= 0 ) {
		arg[0] = (PullDataSource[])pds;
	    } else if (cname.indexOf("PushDataSource") >= 0) {
		arg[0] = (PushDataSource[])pds;
	    } else if (cname.indexOf("PullBufferDataSource") >= 0) {
		arg[0] = (PullBufferDataSource[])pds;
	    } else if (cname.indexOf("PushBufferDataSource") >= 0) {
		arg[0] = (PushBufferDataSource[])pds;
	    } else if ( cname.indexOf("CDPushBDS") >= 0 ) {
		arg[0] = (PushBufferDataSource[])pds;
	    }

	    return (DataSource)(cc.newInstance(arg));
	} catch (Exception ex) {
	}

	return null;
    
public static voidsetHint(int hint, java.lang.Object value)
Specify a hint for the Manager to use.

param
hint The name of the hint to be set.
param
value The value the hint is to be set.
see
#MAX_SECURITY
see
#CACHING
see
#LIGHTWEIGHT_RENDERER
see
#PLUGIN_PLAYER

	if ( (value != null) &&
	     (hint >= 1) &&
	     (hint <= numberOfHints) ) { // if test not really necessary
	    hintTable.put(new Integer(hint), value);
	}