Package javax.media

Source Code of javax.media.Manager$BlockingRealizer

package javax.media;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.media.control.FormatControl;
import javax.media.control.TrackControl;
import javax.media.protocol.CaptureDevice;
import javax.media.protocol.DataSource;
import javax.media.protocol.PullBufferDataSource;
import javax.media.protocol.PullDataSource;
import javax.media.protocol.PushBufferDataSource;
import javax.media.protocol.PushDataSource;
import javax.media.protocol.SourceCloneable;
import javax.media.protocol.URLDataSource;

import net.sf.fmj.media.CloneableCaptureDevicePullBufferDataSource;
import net.sf.fmj.media.CloneableCaptureDevicePullDataSource;
import net.sf.fmj.media.CloneableCaptureDevicePushBufferDataSource;
import net.sf.fmj.media.CloneableCaptureDevicePushDataSource;
import net.sf.fmj.media.CloneablePullBufferDataSource;
import net.sf.fmj.media.CloneablePullDataSource;
import net.sf.fmj.media.CloneablePushBufferDataSource;
import net.sf.fmj.media.CloneablePushDataSource;
import net.sf.fmj.media.MergingCaptureDevicePullBufferDataSource;
import net.sf.fmj.media.MergingCaptureDevicePullDataSource;
import net.sf.fmj.media.MergingCaptureDevicePushBufferDataSource;
import net.sf.fmj.media.MergingCaptureDevicePushDataSource;
import net.sf.fmj.media.MergingPullBufferDataSource;
import net.sf.fmj.media.MergingPullDataSource;
import net.sf.fmj.media.MergingPushBufferDataSource;
import net.sf.fmj.media.MergingPushDataSource;
import net.sf.fmj.utility.LoggerSingleton;

/**
* Standard JMF class -- see <a href="http://java.sun.com/products/java-media/jmf/2.1.1/apidocs/javax/media/Manager.html" target="_blank">this class in the JMF Javadoc</a>.
*
* @author Ken Larson
*
*/
public final class Manager
{
  public static final String FMJ_TAG = "FMJ"// Do not remove - this is used by ClasspathChecker to distinguish this version from JMF's.

  // for strict JMF-compatibility, we are supposed to look for handlers etc starting with "media."
  // in reality, neither JMF or FMJ has any classes that match this, and this has never really been seen anywhere
  // as far as I can tell.  I think the idea was that people could write their own handlers and not have to add
  // a prefix, simply by using "media".  This just causes more failed reflection instantations and hits to
  // the web server if it is an applet.
  // so for strict JMF-compatibility, this should be set to true.
  // see also Registry.READD_JAVAX
  // TODO: we could use hints for these.
  private static final boolean USE_MEDIA_PREFIX = false;
 
 
  private static final Logger logger = LoggerSingleton.logger;
 
  public static final int MAX_SECURITY = 1;

  public static final int CACHING = 2;

  public static final int LIGHTWEIGHT_RENDERER = 3;

  public static final int PLUGIN_PLAYER = 4;

  public static final String UNKNOWN_CONTENT_NAME = "unknown";

  private static TimeBase systemTimeBase = new SystemTimeBase();

  private static final Map<Integer, Object> hints = new HashMap<Integer, Object>();
  static
  {
    hints.put(new Integer(MAX_SECURITY), Boolean.FALSE);
    hints.put(new Integer(CACHING), Boolean.TRUE);
    hints.put(new Integer(LIGHTWEIGHT_RENDERER), Boolean.FALSE);
    hints.put(new Integer(PLUGIN_PLAYER), Boolean.FALSE);

  }

  // one thing that is (was) silly about this connect and retry loop, is that in the case of something like RTP, if
  // there is a timeout connecting to the source, it will then go on and try others.  This would be in
  // the case of an IOException thrown by dataSource.connect, for example.
  // What makes this strange is that the end result is a "No player exception", when it should really rethrow
  // the IOException.  Let's try this.
  public static final boolean RETHROW_IO_EXCEPTIONS = true;
 
  public static String getVersion()
  {
    // try to load fmj.build.properties as a resource, look for build=.
    // this will succeed only for release builds, not when running from
    // CVS.  This allows us to see what build a user is running.
    try
    {
      final Properties p = new Properties();
      p.load(Manager.class.getResourceAsStream("/" + "fmj.build.properties"));
      final String s = p.getProperty("build");
      if (s != null && !s.equals(""))
        return "FMJ " + s.trim();
    }
    catch (Exception e)
    {  // ignore, fall through...
    }
   
    return "FMJ non-release x.x"// this is just a generic reponse when running from CVS or any other source.
   
//    return "2.1.1e"; // for compatibility reasons. Eventually, we should
//              // perhaps have our own version numbering.
  }

  public static Player createPlayer(java.net.URL sourceURL) throws java.io.IOException, NoPlayerException
  {
    return createPlayer(new MediaLocator(sourceURL));
  }

 

 
  public static Player createPlayer(MediaLocator sourceLocator) throws java.io.IOException, NoPlayerException
  {
   
    final String protocol = sourceLocator.getProtocol();
    final Vector dataSourceList = getDataSourceList(protocol);
    for (int i = 0; i < dataSourceList.size(); ++i)
    {
      String dataSourceClassName = (String) dataSourceList.get(i);
      try
      {
        final Class dataSourceClass = Class.forName(dataSourceClassName);
        final DataSource dataSource = (DataSource) dataSourceClass.newInstance();
        dataSource.setLocator(sourceLocator);
        dataSource.connect();
        return createPlayer(dataSource);
       
        // TODO: JMF seems to disconnect data sources in this method, based on this stack trace:
//        java.lang.NullPointerException
//        at com.sun.media.protocol.rtp.DataSource.disconnect(DataSource.java:207)
//        at javax.media.Manager.createPlayer(Manager.java:425)
//        at net.sf.fmj.ui.application.ContainerPlayer.createNewPlayer(ContainerPlayer.java:357)
       
        // TODO: JMF appears to get the streams from the data source (somewhere near) here.  If the stream is null, we get (from JMF:)
//        javax.media.NoPlayerException: Error instantiating class: com.sun.media.content.unknown.Handler : java.io.IOException: Got a null stream from the DataSource
//        at javax.media.Manager.createPlayerForSource(Manager.java:1502)
//        at javax.media.Manager.createPlayer(Manager.java:500)
        // more specifically, it callse getStreams, and if there are no streams or only a null streams, it throws an exception.
        // it then calls isRandomAccess on the stream (or streams?).
       
        // perhaps calling random access is necessary to determine whether some kind of buffered clone of the source is needed
        // OR whether the datasource needs to be closed and re-opened, for the case when one handler is tried, and rejects
        // the source.  If the source is not random access, then you'd have to throw it a way if a handler opened it, read
        // from it, and rejected it.
        // see comments below with URLDataSource connection, below.
        // this is one of the weaknesses of the JMF architecture, that it potentially needs to open a media data source multiple times
        // in order to figure out what to do with it. 
      }
      catch (NoPlayerException e)
      {  // no need to log, will be logged by call to createPlayer.
        continue;
      }
      catch (ClassNotFoundException e)
      {
        logger.finer("createPlayer: "  + e)// no need for call stack
        continue;
      }     
      catch (IOException e)
      {
        logger.log(Level.FINE, ""  + e, e);
        if (RETHROW_IO_EXCEPTIONS)
          throw e;
        else
          continue;
      }
      catch (NoClassDefFoundError e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
      catch (Exception e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }

       
    }
   
    // if none found, try URLDataSource:
    final URL url;
    try
    {
      url = sourceLocator.getURL();
    }
    catch (Exception e)
    {  logger.log(Level.WARNING, ""  + e, e);
      throw new NoPlayerException();
    }
    final URLDataSource dataSource = new URLDataSource(url);
    dataSource.connect()// TODO: there is a problem because we connect to the datasource here, but
                // the following call may try twice or more to use the datasource with a player, once
                // for the right content type, and multiple times for unknown.  The first attempt (for example) may actually
                // read data, in which case the second one will be missing data when it reads.
                // really, the datasource needs to be recreated.
                // The workaround for now is that URLDataSource (and others) allows repeated connect() calls.
    return createPlayer(dataSource);
   
  }

  private static Player createPlayer(DataSource source, String contentType)
    throws java.io.IOException, NoPlayerException
  {
    final List<String> classFoundHandlersTried = new ArrayList<String>()// only include ones where classes were found
    final Vector handlerClassList = getHandlerClassList(contentType);
    for (int i = 0; i < handlerClassList.size(); ++i)
    {
      final String handlerClassName = (String) handlerClassList.get(i);
     
      try
      {
        final Class handlerClass = Class.forName(handlerClassName);
        if (!Player.class.isAssignableFrom(handlerClass) &&
          !MediaProxy.class.isAssignableFrom(handlerClass))
            continue// skip any classes that will not be matched below.
        final MediaHandler handler = (MediaHandler) handlerClass.newInstance();
        handler.setSource(source);
        if (handler instanceof Player)
        {  logger.info("Using player: " + handler.getClass().getName());
          return (Player) handler;
        }
        else if (handler instanceof MediaProxy)
        {
          final MediaProxy mediaProxy = (MediaProxy) handler;
          return createPlayer(mediaProxy.getDataSource());
        }
        else
        {
          logger.fine("Not Player, and not MediaProxy: " + handler.getClass().getName());
          classFoundHandlersTried.add(handlerClassName);

        }
      }
      catch (ClassNotFoundException e)
      {
        // don't add to classFoundHandlersTried
        logger.finer("createPlayer: "  + e)// no need for call stack
        continue;
      }     
      catch (IncompatibleSourceException e)
      {
        classFoundHandlersTried.add(handlerClassName);
        logger.fine("createPlayer(" + source + ", " + contentType + "): "  + e)// no need for call stack
        continue;
      }
      catch (IOException e)
      {
        classFoundHandlersTried.add(handlerClassName);
        logger.log(Level.FINE, ""  + e, e);
        if (RETHROW_IO_EXCEPTIONS)
          throw e;
        else
          continue;
      }
      catch (NoPlayerException e)
      { 
        classFoundHandlersTried.add(handlerClassName);
        // no need to log, will be logged by call to createPlayer.
        continue;
      }
      catch (NoClassDefFoundError e)
      {
        classFoundHandlersTried.add(handlerClassName);
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
      catch (Exception e)
      {
        classFoundHandlersTried.add(handlerClassName);
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
    }
   
    final StringBuilder b = new StringBuilder();
    b.append("Tried handlers:");
    for (int i = 0; i < classFoundHandlersTried.size(); ++i)
    {
      b.append('\n');
      b.append(classFoundHandlersTried.get(i));
   

    }

    // because this exception basically masks exceptions caught above, we'll add some info about what we did
    throw new NoPlayerException("No player found for " + source.getLocator() + " - " + b.toString());
  }
 
 
 
  public static Player createPlayer(DataSource source)
      throws java.io.IOException, NoPlayerException
  {
   
    try
    {
      return createPlayer(source, source.getContentType());
    }
    catch (NoPlayerException e)
    {  // no need to log, will be logged by call to createProcessor.
    }
    catch (IOException e)
    {
      logger.log(Level.FINE, ""  + e, e);
      if (RETHROW_IO_EXCEPTIONS)
        throw e;
    }
    catch (Exception e)
    {
      logger.log(Level.FINER, ""  + e, e);
     
    }
    // TODO: this is dangerous to re-use the same source for another player.
    // this may actually cause it to re-use this source multiple times.
    return createPlayer(source, "unknown");

  }

  public static Player createRealizedPlayer(java.net.URL sourceURL)
      throws java.io.IOException, NoPlayerException,
      CannotRealizeException
  {
    final Player player = createPlayer(sourceURL);
    blockingRealize(player);
    return player;
  }


 
  public static Player createRealizedPlayer(MediaLocator ml)
      throws java.io.IOException, NoPlayerException,
      CannotRealizeException
  {
    final Player player = createPlayer(ml);
    blockingRealize(player);
    return player;
  }

  public static Player createRealizedPlayer(DataSource source)
      throws java.io.IOException, NoPlayerException,
      CannotRealizeException
  {
    final Player player = createPlayer(source);
    blockingRealize(player);
    return player;
  }

  public static Processor createProcessor(java.net.URL sourceURL)
      throws java.io.IOException, NoProcessorException
  {
    return createProcessor(new MediaLocator(sourceURL));
  }

  public static Processor createProcessor(MediaLocator sourceLocator)
      throws java.io.IOException, NoProcessorException
  {
    final String protocol = sourceLocator.getProtocol();
    final Vector dataSourceList = getDataSourceList(protocol);
    for (int i = 0; i < dataSourceList.size(); ++i)
    {
      String dataSourceClassName = (String) dataSourceList.get(i);
      try
      {
        final Class dataSourceClass = Class.forName(dataSourceClassName);
        final DataSource dataSource = (DataSource) dataSourceClass.newInstance();
        dataSource.setLocator(sourceLocator);
        dataSource.connect();
        return createProcessor(dataSource);
       
       
      }
      catch (ClassNotFoundException e)
      {
        logger.finer("createProcessor: "  + e)// no need for call stack
        continue;
      }
      catch (IOException e)
      {
        logger.log(Level.FINE, ""  + e, e);
        if (RETHROW_IO_EXCEPTIONS)
          throw e;
        else
          continue;
      }
      catch (NoProcessorException e)
      {  continue// no need to log, will be logged by call to createProcessor.
      }
      catch (NoClassDefFoundError e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
      catch (Exception e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }

       
    }
   
    // if none found, try URLDataSource:
    final URL url;
    try
    {
      url = sourceLocator.getURL();
    }
    catch (Exception e)
    {  logger.log(Level.WARNING, ""  + e, e);
      throw new NoProcessorException();
    }
    final URLDataSource dataSource = new URLDataSource(url);
    dataSource.connect();
    return createProcessor(dataSource);
  }

  private static Processor createProcessor(DataSource source, String contentType)
      throws java.io.IOException, NoProcessorException
  {
    final Vector handlerClassList = getProcessorClassList(contentType);
    for (int i = 0; i < handlerClassList.size(); ++i)
    {
      final String handlerClassName = (String) handlerClassList.get(i);
     
      try
      {
        final Class handlerClass = Class.forName(handlerClassName);
        if (!Processor.class.isAssignableFrom(handlerClass) &&
          !MediaProxy.class.isAssignableFrom(handlerClass))
            continue// skip any classes that will not be matched below.
        final MediaHandler handler = (MediaHandler) handlerClass.newInstance();
        handler.setSource(source);
        if (handler instanceof Processor)
        {  return (Processor) handler;
        }
        else if (handler instanceof MediaProxy)
        {
          final MediaProxy mediaProxy = (MediaProxy) handler;
          return createProcessor(mediaProxy.getDataSource());
        }
      }
      catch (ClassNotFoundException e)
      {
        logger.finer("createProcessor: "  + e)// no need for call stack
        continue;
      }
      catch (IncompatibleSourceException e)
      {
        logger.fine("createProcessor(" + source + ", " + contentType + "): "  + e)// no need for call stack
        continue;
      }
      catch (NoProcessorException e)
      {  continue// no need to log, will be logged by call to createProcessor.
      }
      catch (IOException e)
      {
        logger.log(Level.FINE, ""  + e, e);
        if (RETHROW_IO_EXCEPTIONS)
          throw e;
        else
          continue;
      }
      catch (NoClassDefFoundError e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
      catch (Exception e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
    }
    throw new NoProcessorException();
  }
 
  public static Processor createProcessor(DataSource source)
      throws java.io.IOException, NoProcessorException
  {
    try
    {
      return createProcessor(source, source.getContentType());
    }
    catch (IOException e)
    {
      logger.log(Level.FINE, ""  + e, e);
      if (RETHROW_IO_EXCEPTIONS)
        throw e;
     
    }
    catch (NoProcessorException e)
    {  // no need to log, will be logged by call to createProcessor.
    }
    catch (Exception e)
    {
      logger.log(Level.FINE, ""  + e, e);
    }
    return createProcessor(source, "unknown");

  }

  public static Processor createRealizedProcessor(ProcessorModel model) throws java.io.IOException, NoProcessorException, CannotRealizeException
  {
    // TODO: verify that this implementation is JMF-compatible
    // TODO: according to http://www.ee.iitm.ac.in/~tgvenky/JMFBook/SampleSections/8.3.pdf,
    // if the model's content descriptor is null, it is to behave like a player.
   
    final Processor processor;
    if (model.getInputDataSource() != null)
      processor = createProcessor(model.getInputDataSource())
    else
      processor = createProcessor(model.getInputLocator());
    // TODO: if model.getInputLocator() is null and ds is null, we are to get a capture device, according to JMF.
   
    final net.sf.fmj.ejmf.toolkit.util.StateWaiter stateWaiter = new net.sf.fmj.ejmf.toolkit.util.StateWaiter(processor);
   
    if (!stateWaiter.blockingConfigure())
      throw new CannotRealizeException("Failed to configure");

    if (model.getContentDescriptor() != null)
      processor.setContentDescriptor(model.getContentDescriptor());

    final Format[] outputFormats;
    int numTracks = model.getTrackCount(Integer.MAX_VALUE);
    if (numTracks > 0)
    {  outputFormats = new Format[numTracks];
      for (int i = 0; i < outputFormats.length; ++i)
        outputFormats[i] = model.getOutputTrackFormat(i);
    }
    else
      outputFormats = null;
   
    if (outputFormats != null && outputFormats.length > 0)
    {
      final TrackControl trackControl[] = processor.getTrackControls();
     
      final boolean[] trackConfigured = new boolean[trackControl.length]// which tracks have been either configured or disabled
      final boolean[] outputFormatUsed = new boolean[outputFormats.length]// which output formats we have found a track for.

      // assign specified formats to compatible tracks:
      for (int j = 0; j < outputFormats.length; ++j)
      {
        final Format outputFormat = outputFormats[j];
        if (outputFormat == null)
        {  // this format does not need to be set.
          continue;
        }
   
        // Go through the tracks and try to program one of them to output the desired format.
   
        for (int i = 0; i < trackControl.length; i++)
        {
          if (trackConfigured[i])
            continue;
         
          if (!(trackControl[i] instanceof FormatControl))
          {
            logger.warning("Disabling track " + i + "; trackControl is not a FormatControl: " + trackControl[i]);
            trackControl[i].setEnabled(false);
            trackConfigured[i] = true;
          }
          else
          {
            if (((FormatControl) trackControl[i]).setFormat(outputFormat) == null)
            {
              logger.fine("Track " + i + "; does not accept " + outputFormat);
            } else
            {
              logger.fine("Using track " + i + "; accepted " + outputFormat);
              trackConfigured[i] = true;
              outputFormatUsed[j] = true;
            }
          }
        }
      }
     
      // any remaining free tracks can be used for any "unspecified" formats.
      for (int j = 0; j < outputFormats.length; ++j)
      {
        final Format outputFormat = outputFormats[j];
        if (outputFormat == null)
        { 
          for (int i = 0; i < trackControl.length; i++)
          {
            if (!trackConfigured[i])
            {
              logger.fine("Using track " + i + "; for unspecified format");
              trackConfigured[i] = true;
              outputFormatUsed[j] = true;
            }
         
          }
        }
      }
     
      // disable any unused tracks
      for (int i = 0; i < trackControl.length; i++)
      {
        if (!trackConfigured[i])
        {
          logger.info("Disabling track " + i + "; no format set.");
          trackControl[i].setEnabled(false);
        }
     
      }
     
      // make sure all formats have been assigned to a track:
      for (int j = 0; j < outputFormats.length; ++j)
      {
        if (!outputFormatUsed[j])
          throw new CannotRealizeException("No tracks found that are compatible with format " + outputFormats[j])// TODO: others that weren't used.
       
      }

    }
   
   
    if (!stateWaiter.blockingRealize())
    {
      throw new CannotRealizeException("Failed to realize");

    }
   
   
    return processor;
  }

  public static DataSource createDataSource(java.net.URL sourceURL)
      throws java.io.IOException, NoDataSourceException
  {
    return createDataSource(new MediaLocator(sourceURL));
  }

  // this method has a fundamental flaw (carried over from JMF): the DataSource may not be
  // accepted by the Handler.  So createPlayer(createDataSource(MediaLocator)) is not equivalent to
  // createPlayer(MediaLocator)
  public static DataSource createDataSource(MediaLocator sourceLocator)
      throws java.io.IOException, NoDataSourceException
  {
    final String protocol = sourceLocator.getProtocol();
    final Vector dataSourceList = getDataSourceList(protocol);
    for (int i = 0; i < dataSourceList.size(); ++i)
    {
      String dataSourceClassName = (String) dataSourceList.get(i);
      try
      {
        final Class dataSourceClass = Class.forName(dataSourceClassName);
        final DataSource dataSource = (DataSource) dataSourceClass.newInstance();
        dataSource.setLocator(sourceLocator);
        dataSource.connect();
        return dataSource;
       
       
      }
      catch (ClassNotFoundException e)
      {
        logger.finer("createDataSource: "  + e)// no need for call stack
        continue;
      }
      catch (IOException e)
      {
        logger.log(Level.FINE, ""  + e, e);
        if (RETHROW_IO_EXCEPTIONS)
          throw e;
        else
          continue;
      }
      catch (NoClassDefFoundError e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
      catch (Exception e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }

       
    }
   
    // if none found, try URLDataSource:
    final URL url;
    try
    {
      url = sourceLocator.getURL();
    }
    catch (Exception e)
    {  logger.log(Level.WARNING, ""  + e, e);
      throw new NoDataSourceException();
    }
    final URLDataSource dataSource = new URLDataSource(url);
    dataSource.connect();
    return dataSource;
  }

  public static DataSource createMergingDataSource(DataSource[] sources) throws IncompatibleSourceException
  {
    // Note: JMF does not return source[0] if sources.length == 1.
    boolean allPushBufferDataSource = true;
    boolean allPullBufferDataSource = true;
    boolean allPushDataSource = true;
    boolean allPullDataSource = true;
    boolean allCaptureDevice = true;
   
    for (DataSource source : sources)
    {
      if (!(source instanceof PushBufferDataSource))
        allPushBufferDataSource = false;
      if (!(source instanceof PullBufferDataSource))
        allPullBufferDataSource = false;
      if (!(source instanceof PushDataSource))
        allPushDataSource = false;
      if (!(source instanceof PullDataSource))
        allPullDataSource = false;
      if (!(source instanceof CaptureDevice))
        allCaptureDevice = false;
    }
   
    if (allPushBufferDataSource)
    {
      final List<PushBufferDataSource> sourcesCast = new ArrayList<PushBufferDataSource>();
      for (DataSource source : sources)
        sourcesCast.add((PushBufferDataSource) source);
      if (allCaptureDevice)
        return new MergingCaptureDevicePushBufferDataSource(sourcesCast);
      else
        return new MergingPushBufferDataSource(sourcesCast);
    }
    else if (allPullBufferDataSource)
    {
      final List<PullBufferDataSource> sourcesCast = new ArrayList<PullBufferDataSource>();
      for (DataSource source : sources)
        sourcesCast.add((PullBufferDataSource) source);
      if (allCaptureDevice)
        return new MergingCaptureDevicePullBufferDataSource(sourcesCast);
      else
        return new MergingPullBufferDataSource(sourcesCast);
    }
    else if (allPushDataSource)
    {
      final List<PushDataSource> sourcesCast = new ArrayList<PushDataSource>();
      for (DataSource source : sources)
        sourcesCast.add((PushDataSource) source);
      if (allCaptureDevice)
        return new MergingCaptureDevicePushDataSource(sourcesCast);
      else
        return new MergingPushDataSource(sourcesCast);
    }
    else if (allPullDataSource)
    {
      final List<PullDataSource> sourcesCast = new ArrayList<PullDataSource>();
      for (DataSource source : sources)
        sourcesCast.add((PullDataSource) source);
      if (allCaptureDevice)
        return new MergingCaptureDevicePullDataSource(sourcesCast);
      else
        return new MergingPullDataSource(sourcesCast);
    }
    else
    throw new IncompatibleSourceException();
    }

  }

  public static DataSource createCloneableDataSource(DataSource source)
  {
    // TODO: according to the JMF architecture guide:
    // "The clones don't necessarily have the same properties as the cloneable data source used to create them or the original DataSource. For example, a cloneable data source created for a capture device might function as a master data source for its clones--in this case, unless the cloneable data source is used, the clones won't produce any data. If you hook up both the cloneable data source and one or more clones, the clones will produce data at the same rate as the master."
    // TODO: FMJ's clones don't work in this master/slave fashion.

    if (source instanceof SourceCloneable)
      return source; 
   
    if (source instanceof PushBufferDataSource)
    {  if (source instanceof CaptureDevice)
        return new CloneableCaptureDevicePushBufferDataSource((PushBufferDataSource) source);
      else
        return new CloneablePushBufferDataSource((PushBufferDataSource) source);
    }
    else if (source instanceof PullBufferDataSource)
    {  if (source instanceof CaptureDevice)
        return new CloneableCaptureDevicePullBufferDataSource((PullBufferDataSource) source);
      else
        return new CloneablePullBufferDataSource((PullBufferDataSource) source);
    }
    else if (source instanceof PushDataSource)
    {  if (source instanceof CaptureDevice)
        return new CloneableCaptureDevicePushDataSource((PushDataSource) source);
      else
        return new CloneablePushDataSource((PushDataSource) source);
    }
    else if (source instanceof PullDataSource)
    {  if (source instanceof CaptureDevice)
        return new CloneableCaptureDevicePullDataSource((PullDataSource) source);
      else
        return new CloneablePullDataSource((PullDataSource) source);
    }
    else
      throw new IllegalArgumentException("Unknown or unsupported DataSource type: " + source);

   
  }

  public static TimeBase getSystemTimeBase()
  {
    return systemTimeBase;
  }

  // does not handle proxies.
  private static DataSink createDataSink(DataSource datasource,
      String protocol) throws NoDataSinkException
  {
    final Vector handlerClassList = getDataSinkClassList(protocol);
   
    for (int i = 0; i < handlerClassList.size(); ++i)
    {
      final String handlerClassName = (String) handlerClassList.get(i);
     
      try
      {
        final Class handlerClass = Class.forName(handlerClassName);
        if (!DataSink.class.isAssignableFrom(handlerClass))
          continue// skip any classes that will not be matched below.

        final MediaHandler handler = (MediaHandler) handlerClass.newInstance();
        handler.setSource(datasource);
        if (handler instanceof DataSink)
        {  return (DataSink) handler;
        }
       
      }
      catch (ClassNotFoundException e)
      {
        logger.finer("createDataSink: "  + e)// no need for call stack
        continue;
      }     
      catch (IncompatibleSourceException e)
      {
        logger.fine("createDataSink(" + datasource + ", " + protocol + "): "  + e)// no need for call stack
        continue;
      }
      catch (NoClassDefFoundError e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
      catch (Exception e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
    }
    throw new NoDataSinkException();
  }
 
  public static DataSink createDataSink(DataSource datasource, MediaLocator destLocator) throws NoDataSinkException
  {
    final String protocol = destLocator.getProtocol();
   
    final Vector handlerClassList = getDataSinkClassList(protocol);
   
    for (int i = 0; i < handlerClassList.size(); ++i)
    {
      final String handlerClassName = (String) handlerClassList.get(i);
     
      try
      {
        final Class handlerClass = Class.forName(handlerClassName);
        if (!DataSink.class.isAssignableFrom(handlerClass) &&
          !DataSinkProxy.class.isAssignableFrom(handlerClass))
            continue// skip any classes that will not be matched below.

        final MediaHandler handler = (MediaHandler) handlerClass.newInstance();
        handler.setSource(datasource);
        if (handler instanceof DataSink)
        {  DataSink dataSink = (DataSink) handler;
          dataSink.setOutputLocator(destLocator);
          return dataSink;
        }
        else if (handler instanceof DataSinkProxy)
        {
//          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
          final DataSinkProxy mediaProxy = (DataSinkProxy) handler;
         
          final Vector handlerClassList2 = getDataSinkClassList(protocol + "." + toPackageFriendly(mediaProxy.getContentType(destLocator)));
         
          for (int j = 0; j < handlerClassList2.size(); ++j)
          {
            final String handlerClassName2 = (String) handlerClassList2.get(j);
           
            try
            {
              final Class handlerClass2 = Class.forName(handlerClassName2);
              if (!DataSink.class.isAssignableFrom(handlerClass2))
                continue// skip any classes that will not be matched below.
              final MediaHandler handler2 = (MediaHandler) handlerClass2.newInstance();
              handler2.setSource(mediaProxy.getDataSource());
              if (handler2 instanceof DataSink)
              {  DataSink dataSink = (DataSink) handler2;
                dataSink.setOutputLocator(destLocator);
                return (DataSink) handler2;
              }
             
            }
            catch (ClassNotFoundException e)
            {
              logger.finer("createDataSink: "  + e)// no need for call stack
              continue;
            }
            catch (IncompatibleSourceException e)
            {
              logger.fine("createDataSink(" + datasource + ", " + destLocator + "), proxy=" + mediaProxy.getDataSource() + ": "  + e)// no need for call stack
              continue;
            }
            catch (NoClassDefFoundError e)
            {
              logger.log(Level.FINE, ""  + e, e);
              continue;
            }
            catch (Exception e)
            {
              logger.log(Level.FINE, ""  + e, e);
              continue;
            }
          }

        }
      }
      catch (ClassNotFoundException e)
      {
        logger.finer("createDataSink: "  + e)// no need for call stack
        continue;
      }
      catch (IncompatibleSourceException e)
      {
        logger.fine("createDataSink(" + datasource + ", " + destLocator + "): "  + e)// no need for call stack
        continue;
      }
      catch (NoClassDefFoundError e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
      catch (Exception e)
      {
        logger.log(Level.FINE, ""  + e, e);
        continue;
      }
    }
   
    throw new NoDataSinkException();
   
  }
 
  private static void blockingRealize(Controller controller) throws CannotRealizeException
 
    try
    {
      new BlockingRealizer(controller).realize();
    } catch (InterruptedException e)
    {
      throw new CannotRealizeException("Interrupted");
    }
  }
 
  private static class BlockingRealizer implements ControllerListener
  {
    private final Controller controller;

    private volatile boolean realized = false;
    private volatile boolean busy = true;
    private volatile String cannotRealizeExceptionMessage;

    public void realize() throws CannotRealizeException, InterruptedException
    {
      controller.addControllerListener(this);
      controller.realize();
      while (busy)
      {
        try
        {
          synchronized (this)
          {
            wait();
          }
        } catch (InterruptedException e)
        {
          controller.removeControllerListener(this);
          throw e;
        }
      }
      controller.removeControllerListener(this);
     
      if (!realized)
        throw new CannotRealizeException(cannotRealizeExceptionMessage);
    }
   
      public synchronized void controllerUpdate(ControllerEvent event)
    {
      if (event instanceof RealizeCompleteEvent)
      {
        realized = true;
        busy = false;
        notify();
      }
      else if (event instanceof StopEvent || event instanceof ControllerClosedEvent)
      {
        if (event instanceof StopEvent)
        {  cannotRealizeExceptionMessage = "Cannot realize: received StopEvent: " + event;
          logger.info(cannotRealizeExceptionMessage);
        }
        else //if (event instanceof ControllerClosedEvent)
        cannotRealizeExceptionMessage = "Cannot realize: received ControllerClosedEvent: " + event + "; message: " + ((ControllerClosedEvent) event).getMessage();
          logger.info(cannotRealizeExceptionMessage);
        }
       
        realized = false;
        busy = false;
        notify();
      }
    }

    public BlockingRealizer(Controller controller)
    {
      super();
      this.controller = controller;
    }
  }
 


  public static String getCacheDirectory()
  {
    return System.getProperty("java.io.tmpdir");
  }

  public static void setHint(int hint, Object value)
  {
    hints.put(hint, value);
  }

  public static Object getHint(int hint)
  {
    return hints.get(hint);
  }

  public static Vector getDataSourceList(String protocolName)
  {
    return getClassList(protocolName, PackageManager.getProtocolPrefixList(), "protocol", "DataSource");

  }

  private static char toPackageFriendly(char c)
  {  if (c >= 'a' && c <= 'z')
      return c;
    else if (c >= 'A' && c <= 'Z')
      return c;
    else if (c >= '0' && c <= '9')
      return c;
    else if (c == '.')
      return c;
    else if (c == '/')
      return '.';
    else
      return '_';
  }
 
  private static String toPackageFriendly(String contentName)
  {
    final StringBuffer b = new StringBuffer();
    for (int i = 0; i < contentName.length(); ++i)
    { 
      final char c = contentName.charAt(i);
      b.append(toPackageFriendly(c));
    }
    return b.toString();
  }
 

  public static Vector getClassList(String contentName, Vector packages, String component2, String className)
  {
   
    final Vector result = new Vector();
    if (USE_MEDIA_PREFIX)
      result.add("media." + component2 + "." + contentName + "." + className);
   
    for (int i = 0; i < packages.size(); ++i)
    {
      result.add(((String) packages.get(i)) +".media." + component2 + "." + contentName + "." + className);
    }
   
    return result;
  }

  public static Vector getDataSinkClassList(String contentName)
  {
    return getClassList(toPackageFriendly(contentName), PackageManager.getContentPrefixList(), "datasink", "Handler");
 
  }
  public static Vector getHandlerClassList(String contentName)
  {
    return getClassList(toPackageFriendly(contentName), PackageManager.getContentPrefixList(), "content", "Handler");
 
  }

  public static Vector getProcessorClassList(String contentName)
  {
    return getClassList(toPackageFriendly(contentName), PackageManager.getContentPrefixList(), "processor", "Handler");
  }
}
TOP

Related Classes of javax.media.Manager$BlockingRealizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.