/* * @(#)BasicModule.java 1.23 02/08/21 * * Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved. */ package com.sun.media; import javax.media.*; import javax.media.format.*; /** * BasicModule * Implements a basic JMF Module. */ abstract public class BasicModule implements Module, StateTransistor { /** * registry of all input connectors created by this module. */ protected Registry inputConnectors = new Registry(); /** * registry of all output connectors created by this module. */ protected Registry outputConnectors = new Registry(); protected InputConnector[] inputConnectorsArray; protected OutputConnector[] outputConnectorsArray; protected int protocol = Connector.ProtocolPush; /** * the instance name of the module, declared in the manager */ protected String name = null; protected ModuleListener moduleListener; protected BasicController controller; // the Controller that maintains this module. protected boolean resetted = false; protected boolean prefetchFailed = false; protected JMD jmd = null; /** * This function performs the steps of realizing a module or a Player. * @return true if successful. */ public boolean doRealize() { return true; } /** * Called when realize fails. */ public void doFailedRealize() { } /** * Called when the realize() is aborted, i.e. deallocate() was called * while realizing. Release all resources claimed previously by the * realize() call. */ public void abortRealize() { } public void connectorPushed(InputConnector inputConnector) { process(); } /** * This function performs the steps to prefetch a module or Player. * @return true if successful. */ public boolean doPrefetch() { // commit connectors to array resetted = false; return true; } /** * Called when prefetch fails. */ public void doFailedPrefetch() { } /** * Called when the prefetch() is aborted, i.e. deallocate() was called * while prefetching. Release all resources claimed previously by the * prefetch call. */ public void abortPrefetch() { } /** * This function performs the steps to start a module or Player. */ public void doStart() { resetted = false; } /** * This function performs the steps to stop a module or Player, * and return to the prefetched state. */ public void doStop() { } /** * This function performs the steps to deallocate a module or Player, * and return to the realized state. */ public void doDealloc() { } /** * This function performs the steps to close a module or Player. */ public void doClose() { } /** * This function notifies the module that the media time has changed. */ public void doSetMediaTime(Time t) { } /** * This function notifies the module that the playback rate has changed. */ public float doSetRate(float r) { return r; } /** * Return a list of module controls. */ public Object[] getControls() { return null; } public Object getControl(String s) { return null; } /** * Specify a <code>ModuleListener</code> to which this <code>Module</code> * will send events. * * @param listener The listener to which the <code>Module</code> will * post events. */ public void setModuleListener(ModuleListener listener) { moduleListener = listener; } /** * Selects a format for this Connector (the default is null). * The <b>setFormat()</b> method is typically called by the Manager * as part of the Connector connection method call. * Typically the connector would delegate this call to its owning Module. **/ public void setFormat(Connector connector,Format format) {} /** * Return an array of strings containing this media module's input * port names. */ public String[] getInputConnectorNames() { return inputConnectors.getNames(); } /** * Return an array of strings containing this media module's output * port names. */ public String[] getOutputConnectorNames() { return outputConnectors.getNames(); } /** * Return the InputConnector given the connector name. */ public InputConnector getInputConnector(String connectorName) { return (InputConnector)inputConnectors.get(connectorName); } /** * Return the OutputConnector given the connector name. */ public OutputConnector getOutputConnector(String connectorName) { return (OutputConnector)outputConnectors.get(connectorName); } /** * For each of the inputConnectables to this node, it needs to be * registered with this function. */ public void registerInputConnector(String name, InputConnector inputConnector) { inputConnectors.put(name , inputConnector); inputConnector.setModule(this); } /** * For each of the outputConnectables from this node, it needs to be * registered with this function. */ public void registerOutputConnector(String name, OutputConnector outputConnector) { outputConnectors.put(name , outputConnector); outputConnector.setModule(this); } /** * reset this module only. * <pre> * if (state== Started) * throw Exception() * for (all connectors) * connector.reset() * </pre> * The resetted flag is falsified only when the module is later restarted. */ public void reset() { resetted = true; } /** * Verify to see if the given buffer has valid data sizes. */ protected boolean verifyBuffer(Buffer buffer) { if (buffer.isDiscard()) return true; Object data = buffer.getData(); if (buffer.getLength() < 0) { System.err.println("warning: data length shouldn't be negative: " + buffer.getLength()); } if (data == null) { System.err.println("warning: data buffer is null"); if (buffer.getLength() != 0) { System.err.println("buffer advertized length = " + buffer.getLength() + " but data buffer is null!"); return false; } } else if (data instanceof byte[]) { if (buffer.getLength() > ((byte[])data).length) { System.err.println("buffer advertized length = " + buffer.getLength() + " but actual length = " + ((byte[])data).length); return false; } } else if (data instanceof int[]) { if (buffer.getLength() > ((int[])data).length) { System.err.println("buffer advertized length = " + buffer.getLength() + " but actual length = " + ((int[])data).length); return false; } } return true; } /** * @return true if the module has been interrupted. */ final public boolean isInterrupted() { return (controller == null ? false : controller.isInterrupted()); } /** * return if this module create threads (so it run on Safe protocol) * like Rendering module or not (as a codec module). **/ public boolean isThreaded(){ return true; } /** * return if data is available on all inputConnectors and there * is room in all outputConnectors. **/ public boolean canRun(){ for (int i=0;i<inputConnectorsArray.length;i++) if (!inputConnectorsArray[i].isValidBufferAvailable() ) return false; for (int i=0;i<outputConnectorsArray.length;i++) if (!outputConnectorsArray[i].isEmptyBufferAvailable() ) return false; return true; } /** * function which does the real processing. * <pre> * if canRun { * for (all inputConnectors) * ic.getValidBuffer() * for (all outputConnectors) * oc.getEmptyBuffer() * <process buffer> * for (all inputConnectors) * ic.readReport() * for (all outputConnectors) * oc.writeReport() * } * </pre> **/ abstract protected void process(); protected void error(){ throw new RuntimeException(getClass().getName()+" error"); } /** * @return the Controller that maintains this module. **/ final public BasicController getController(){ return controller; } /** * Set the Controller that maintains this module. */ final public void setController(BasicController c) { controller = c; } /** * Return the state of the controller. */ final public int getState() { return controller.getState(); } /** * returns the name of this Module in the Player */ final public String getName(){ return name; } /** * sets the name of this Module. Called by the owning Player * registerModule() method */ public void setName(String name){ this.name=name; } public void setJMD(JMD jmd) { this.jmd = jmd; } /** * Return the current Media time. */ public Time getMediaTime() { return controller.getMediaTime(); } /** * Return the current time in nanoseconds. */ public long getMediaNanoseconds() { return controller.getMediaNanoseconds(); } public long getLatency() { return ((PlaybackEngine)controller).getLatency(); } /** * sets the protocol for all the connectors */ public void setProtocol(int protocol){ this.protocol=protocol; Connector[] connectors= inputConnectors.getConnectors(); for (int i=0; i<connectors.length; i++) connectors[i].setProtocol(protocol); connectors= outputConnectors.getConnectors(); for (int i=0; i<connectors.length ; i++) connectors[i].setProtocol(protocol); } /** * return the data transfer protocol */ public int getProtocol(){ return protocol; } public boolean prefetchFailed() { return prefetchFailed; } ///////////////////////////////////// // inner classes ///////////////////////////////////// /** * Connectors Registry. **/ class Registry extends java.util.Hashtable { Connector def = null; // the Default connector. /** returns the names of all Connectors in this Registry **/ String[] getNames (){ java.util.Enumeration namesEnum=keys(); String[] namesArray=new String[size()]; for (int i=0;i<size();i++) namesArray[i]=(String)namesEnum.nextElement(); return namesArray; } /** register Connector. * @exception RuntimeException If the specified name is already registered **/ void put(String name, Connector connector) { if (containsKey(name)) throw new RuntimeException("Connector '"+name+"' already exists in Module '"+BasicModule.this.getClass().getName()+"::"+name+"'"); if (def == null) def = connector; super.put(name,connector); } /** * Return the default if null (wildcard) is passed in. */ Object get(String name) { if (name == null) return def; return super.get(name); } /** returns all Connectors in this Registry **/ Connector[] getConnectors (){ java.util.Enumeration connectorsEnum=elements(); Connector[] connectorsArray=new Connector[size()]; for (int i=0;i<size();i++) connectorsArray[i]=(Connector)connectorsEnum.nextElement(); return connectorsArray; } } }