All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.fmj.ejmf.toolkit.media.AbstractClock Maven / Gradle / Ivy

There is a newer version: 1.0.2-jitsi
Show newest version
package net.sf.fmj.ejmf.toolkit.media;

import javax.media.*;

/**
 * The AbstractClock provides an abstract implementation of the
 * javax.media.Clock interface. All methods are implemented except for
 * setStopTime() and getStopTime(). These methods will invariably require
 * implementation-specific functionality and therefore are left to the
 * subclasses to implement.
 *
 * From the book: Essential JMF, Gordon, Talley (ISBN 0130801046). Used with
 * permission.
 *
 * @see AbstractController
 * @see StopTimeMonitor
 *
 * @author Steve Talley & Rob Gordon
 */
public class AbstractClock implements Clock
{
    private TimeBase systemtimebase = Manager.getSystemTimeBase();
    private TimeBase timebase = systemtimebase;
    private Time mediaStartTime = new Time(0);
    private Time mediaStopTime = Clock.RESET;
    private Time timeBaseStartTime;
    private float rate = 1.0F;
    private boolean isStarted = false;

    /**
     * Constructs an AbstractClock.
     */
    public AbstractClock()
    {
        super();
    }

    // //////////////////////////////////////////////////////
    //
    // javax.media.Clock methods
    //
    // //////////////////////////////////////////////////////

    /**
     * Calculates the media time on a started Clock based on the assumption that
     * the Clock is started.
     */
    private synchronized Time calculateMediaTime()
    {
        long tbCurrent = timebase.getNanoseconds();
        long tbStart = timeBaseStartTime.getNanoseconds();

        // If we are scheduled to start but haven't yet reached
        // the scheduled start time, return the media start time
        if (tbCurrent < tbStart)
        {
            return mediaStartTime;
        }

        long mStart = mediaStartTime.getNanoseconds();
        long mCurrent = (long) ((tbCurrent - tbStart) * rate + mStart);

        return new Time(mCurrent);
    }

    /**
     * Get the media time in nanoseconds.
     */
    public synchronized long getMediaNanoseconds()
    {
        return getMediaTime().getNanoseconds();
    }

    /**
     * Get the media time the media is scheduled to start (if the Clock is
     * stopped), or the media time at which the Clock started (if the Clock is
     * started).
     */
    protected Time getMediaStartTime()
    {
        return mediaStartTime;
    }

    /**
     * Calculates the current media time based on the current time-base time,
     * the time-base start time, the media start time, and the rate.
     *
     * @return The current media time
     */
    public synchronized Time getMediaTime()
    {
        if (!isStarted)
        {
            // If the Clock is stopped return it's starting
            // media-time
            return mediaStartTime;
        } else
        {
            // Calculate the media time
            return calculateMediaTime();
        }
    }

    /**
     * Get the current temporal scale factor. The scale factor defines the
     * relationship between the Clock's media time and its
     * TimeBase.
     * 

* For example, a rate of 2.0 indicates that media time will pass * twice as fast as the TimeBase time once the Clock * starts. Similarly, a negative rate indicates that the Clock runs * in the opposite direction of its TimeBase. All Clocks * are guaranteed to support a rate of 1.0, the default rate. * Clocks are not required to support any other rate. *

*/ public synchronized float getRate() { return rate; } /** * Get the last value successfully set by setStopTime. Returns the constant * Clock.RESET if no stop time is set * * @return The current stop time. */ public synchronized Time getStopTime() { return mediaStopTime; } /** * Gets the time until the Clock's media synchronizes with its time-base. * * @return The time remaining until the time-base start-time if this Clock * is Started and the time-base start-time has not yet been reached, * or the media time otherwise. */ public synchronized Time getSyncTime() { if (isStarted) { long startNano = timeBaseStartTime.getNanoseconds(); long nowNano = getTimeBase().getNanoseconds(); if (startNano >= nowNano) { return new Time((nowNano - startNano)); } } return getMediaTime(); } /** * Get the TimeBase that this Clock is using. */ public synchronized TimeBase getTimeBase() { return timebase; } /** * Get the time-base time the media is scheduled to start (if the Clock is * stopped), or the time-base time at which the Clock started (if the Clock * is started). */ protected Time getTimeBaseStartTime() { return timeBaseStartTime; } /** * Given a media time, returns the corresponding time-base time. Uses the * current rate, the time-base start time, and the media start time to * calculate. * * @param t * A media time to be mapped to a time-base time. * * @return A time-base time. * * @exception ClockStoppedException * If the clock has not started. */ public synchronized Time mapToTimeBase(Time t) throws ClockStoppedException { if (!isStarted) { throw new ClockStoppedException( "Cannot map media time to time-base time on a Stopped Clock"); } long mCurrent = t.getNanoseconds(); long mStart = mediaStartTime.getNanoseconds(); long tbStart = timeBaseStartTime.getNanoseconds(); return new Time((long) (((mCurrent - mStart) / rate) + tbStart)); } /** * Sets the media time. * * @param t * The media time to set * * @exception ClockStartedError * If the Clock is Started. */ public synchronized void setMediaTime(Time t) { if (isStarted) { throw new ClockStartedError( "Cannot set media time on a Started Clock"); } mediaStartTime = t; } /** * Set the temporal scale factor. The argument suggests the scale * factor to use. *

* The setRate method returns the actual rate set by the * Clock. Clocks should set their rate as close to the * requested value as possible, but are not required to set the rate to the * exact value of any argument other than 1.0. A Clock is only * guaranteed to set its rate exactly to 1.0. * * @param rate * The temporal scale factor (rate) to set. * * @exception ClockStartedError * If the Clock is Started. * * @return The actual rate set. * */ public synchronized float setRate(float rate) { if (isStarted) { throw new ClockStartedError("Cannot set rate on a Started Clock"); } if (rate != 0.0F) { this.rate = rate; } return this.rate; } /** * Set the media time at which you want the Clock to stop. * The Clock will stop when its media time passes the * stop-time. To clear the stop time, set it to: Clock.RESET. *

* You can always call setStopTime on a Stopped * Clock. *

* On a Started Clock, the stop-time can only be set * once. A StopTimeSetError is thrown if * setStopTime is called and the media stop-time has already * been set. * * @param mediaStopTime * The time at which you want the Clock to stop, in * media time. */ public synchronized void setStopTime(Time mediaStopTime) { if (isStarted && this.mediaStopTime != RESET) { throw new StopTimeSetError( "Stop time may be set only once on a Started Clock"); } this.mediaStopTime = mediaStopTime; } /** * Set the TimeBase for this Clock. This method can only * be called on a Stopped Clock. A * ClockStartedError is thrown if setTimeBase is called on * a Started Clock. *

* A Clock has a default TimeBase that is determined by * the implementation. To reset a Clock to its default * TimeBase, call setTimeBase(null). * * @param timebase * The new TimeBase or null to reset the * Clock to its default TimeBase. * * @exception IncompatibleTimeBaseException * Thrown if the Clock can't use the specified * TimeBase. */ public synchronized void setTimeBase(TimeBase timebase) throws IncompatibleTimeBaseException { if (isStarted) { throw new ClockStartedError( "Cannot set time base on a Started Clock"); } if (timebase == null) { this.timebase = systemtimebase; } else { this.timebase = timebase; } } /** * Stop the Clock. */ public synchronized void stop() { if (isStarted) { mediaStartTime = calculateMediaTime(); // KAL: TODO: what is the // reason for this? // Commented out -- is this necessary? // timeBaseStartTime = timebase.getTime(); isStarted = false; } } /** * syncStart the AbstractClock at the previously- specified time-base start * time. *

* Synchronous method -- return when transition complete */ public synchronized void syncStart(Time t) { // Enforce state prereqs if (isStarted) { throw new ClockStartedError( "syncStart() cannot be called on a started Clock"); } long now = getTimeBase().getNanoseconds(); long start = t.getNanoseconds(); if (start - now > 0) { // Start time is in the future // Set the time-base start time this.timeBaseStartTime = new Time(start); } else { // Start time is in the past // Set the time-base start time to be now this.timeBaseStartTime = new Time(now); } isStarted = true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy