diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/AbstractPushBufferCaptureDevice.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/AbstractPushBufferCaptureDevice.java new file mode 100644 index 000000000..c1de5f249 --- /dev/null +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/AbstractPushBufferCaptureDevice.java @@ -0,0 +1,624 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.neomedia.jmfext.media.protocol; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import javax.media.*; +import javax.media.control.*; +import javax.media.protocol.*; + +import net.java.sip.communicator.impl.neomedia.control.*; +import net.java.sip.communicator.util.*; + +/** + * Provides a base implementation of PushBufferDataSource and + * CaptureDevice in order to facilitate implementers by taking care of + * boilerplate in the most common cases. + * + * @author Lubomir Marinov + */ +public abstract class AbstractPushBufferCaptureDevice + extends PushBufferDataSource + implements CaptureDevice +{ + + /** + * The Logger used by the AbstractPushBufferCaptureDevice + * class and its instances for logging output. + */ + private static final Logger logger + = Logger.getLogger(AbstractPushBufferCaptureDevice.class); + + /** + * The value of the formatControls property of + * AbstractPushBufferCaptureDevice which represents an empty array + * of FormatControls. Explicitly defined in order to reduce + * unnecessary allocations. + */ + protected static final FormatControl[] EMPTY_FORMAT_CONTROLS + = new FormatControl[0]; + + /** + * The value of the streams property of + * AbstractPushBufferCaptureDevice which represents an empty array + * of PushBufferStreams. Explicitly defined in order to reduce + * unnecessary allocations. + */ + protected static final PushBufferStream[] EMPTY_STREAMS + = new PushBufferStream[0]; + + /** + * The indicator which determines whether a connection to the media source + * specified by the MediaLocator of this DataSource has + * been opened. + */ + private boolean connected = false; + + /** + * The array of FormatControl instances each one of which can be + * used before {@link #connect()} to get and set the capture Format + * of each one of the capture streams. + */ + private FormatControl[] formatControls; + + /** + * The indicator which determines whether the transfer of media data from + * this DataSource has been started. + */ + private boolean started = false; + + /** + * The PushBufferStreams through which this + * PushBufferDataSource gives access to its media data. + */ + private AbstractPushBufferStream[] streams; + + /** + * Initializes a new AbstractPushBufferCaptureDevice instance. + */ + protected AbstractPushBufferCaptureDevice() + { + } + + /** + * Initializes a new AbstractPushBufferCaptureDevice instance from + * a specific MediaLocator. + * + * @param locator the MediaLocator to create the new instance from + */ + protected AbstractPushBufferCaptureDevice(MediaLocator locator) + { + setLocator(locator); + } + + /** + * Determines whether it is allowed to set the format of a specific + * FormatControl of the PushBufferStream of this + * PushBufferDataSource with a specific index to a specific + * Format. The AbstractPushBufferCaptureDevice + * implementation always returns false. + * + * @param format the Format which is to be set + * @param streamIndex the zero-based index of the PushBufferStream + * in the list of streams of this PushBufferDataSource which is to + * have its Format set + * @param formatControl the FormatControl of the stream through + * which the set request is received + * @return true if the specified Format is to be set as + * the format of formatControl; otherwise, false + */ + protected boolean canSetFormat( + Format format, + int streamIndex, + FormatControl formatControl) + { + return false; + } + + /** + * Opens a connection to the media source specified by the + * MediaLocator of this DataSource. + * + * @throws IOException if anything goes wrong while opening the connection + * to the media source specified by the MediaLocator of this + * DataSource + */ + public synchronized void connect() + throws IOException + { + if (!connected) + { + doConnect(); + connected = true; + } + } + + /** + * Creates a new FormatControl instance which is to be associated + * with a PushBufferStream at a specific zero-based index in the + * list of streams of this PushBufferDataSource. As the + * FormatControls of a PushBufferDataSource can be + * requested before {@link #connect()}, its PushBufferStreams may + * not exist at the time of the request for the creation of the + * FormatControl. + * + * @param streamIndex the zero-based index of the PushBufferStream + * in the list of streams of this PushBufferDataSource which is to + * be associated with the new FormatControl instance + * @return a new FormatControl instance which is to be associated + * with a PushBufferStream at the specified streamIndex in + * the list of streams of this PushBufferDataSource + */ + protected FormatControl createFormatControl(final int streamIndex) + { + return + new AbstractFormatControl() + { + /** + * The Format of this FormatControl and, + * respectively, of the media data of its owner. + */ + private Format format; + + /** + * Gets the Format of the media data of the owner of + * this FormatControl. + * + * @return the Format of the media data of the owner of + * this FormatControl + */ + public Format getFormat() + { + if (format == null) + format + = AbstractPushBufferCaptureDevice.this + .getFormat(streamIndex, this); + return format; + } + + /** + * Gets the Formats in which the owner of this + * FormatControl is capable of providing media data. + * + * @return an array of Formats in which the owner of + * this FormatControl is capable of providing media + * data + */ + public Format[] getSupportedFormats() + { + return + AbstractPushBufferCaptureDevice.this + .getSupportedFormats(streamIndex, this); + } + + /** + * Implements {@link FormatControl#setFormat(Format)}. Attempts + * to set the Format in which the owner of this + * FormatControl is to provide media data. + * + * @param format the Format to be set on this instance + * @return the currently set Format after the attempt + * to set it on this instance if format is supported by + * this instance and regardless of whether it was actually set; + * null if format is not supported by this + * instance + */ + @Override + public Format setFormat(Format format) + { + format = super.setFormat(format); + + if ((format != null) + && canSetFormat(format, streamIndex, this)) + this.format = format; + return getFormat(); + } + }; + } + + /** + * Creates the FormatControls of this CaptureDevice. + * + * @return an array of the FormatControls of this + * CaptureDevice + */ + protected FormatControl[] createFormatControls() + { + FormatControl formatControl = createFormatControl(0); + + return + (formatControl == null) + ? EMPTY_FORMAT_CONTROLS + : new FormatControl[] { formatControl }; + } + + /** + * Create a new PushBufferStream which is to be at a specific + * zero-based index in the list of streams of this + * PushBufferDataSource. The Format-related information of + * the new instance is to be abstracted by a specific + * FormatControl. + * + * @param streamIndex the zero-based index of the PushBufferStream + * in the list of streams of this PushBufferDataSource + * @param formatControl the FormatControl which is to abstract the + * Format-related information of the new instance + * @return a new PushBufferStream which is to be at the specified + * streamIndex in the list of streams of this + * PushBufferDataSource and which has its Format-related + * information abstracted by the specified formatControl + */ + protected abstract AbstractPushBufferStream createStream( + int streamIndex, + FormatControl formatControl); + + /** + * Closes the connection to the media source specified by the + * MediaLocator of this DataSource. If such a connection + * has not been opened, the call is ignored. + */ + public synchronized void disconnect() + { + try + { + stop(); + } + catch (IOException ioex) + { + logger.error("Failed to stop " + getClass().getSimpleName(), ioex); + } + + if (connected) + { + doDisconnect(); + connected = false; + } + } + + /** + * Opens a connection to the media source specified by the + * MediaLocator of this DataSource. Allows extenders to + * override and be sure that there will be no request to open a connection + * if the connection has already been opened. + * + * @throws IOException if anything goes wrong while opening the connection + * to the media source specified by the MediaLocator of this + * DataSource + */ + protected synchronized void doConnect() + throws IOException + { + } + + /** + * Closes the connection to the media source specified by the + * MediaLocator of this DataSource. Allows extenders to + * override and be sure that there will be no request to close a connection + * if the connection has not been opened yet. + */ + protected synchronized void doDisconnect() + { + if (streams != null) + try + { + for (AbstractPushBufferStream stream : streams) + stream.close(); + } + finally + { + streams = null; + } + } + + /** + * Starts the transfer of media data from this DataSource. Allows + * extenders to override and be sure that there will be no request to start + * the transfer of media data if it has already been started. + * + * @throws IOException if anything goes wrong while starting the transfer of + * media data from this DataSource + */ + protected synchronized void doStart() + throws IOException + { + if (streams != null) + for (AbstractPushBufferStream stream : streams) + stream.start(); + } + + /** + * Stops the transfer of media data from this DataSource. Allows + * extenders to override and be sure that there will be no request to stop + * the transfer of media data if it has not been started yet. + * + * @throws IOException if anything goes wrong while stopping the transfer of + * media data from this DataSource + */ + protected synchronized void doStop() + throws IOException + { + if (streams != null) + for (AbstractPushBufferStream stream : streams) + stream.stop(); + } + + /** + * Gets the CaptureDeviceInfo of this CaptureDevice which + * describes it. + * + * @return the CaptureDeviceInfo of this CaptureDevice + * which describes it + */ + public CaptureDeviceInfo getCaptureDeviceInfo() + { + return getCaptureDeviceInfo(this); + } + + /** + * Gets the CaptureDeviceInfo of a specific CaptureDevice + * by locating its registration in JMF using its MediaLocator. + * + * @param captureDevice the CaptureDevice to gets the + * CaptureDeviceInfo of + * @return the CaptureDeviceInfo of the specified + * CaptureDevice as registered in JMF + */ + public static CaptureDeviceInfo getCaptureDeviceInfo( + DataSource captureDevice) + { + /* + * TODO The implemented search for the CaptureDeviceInfo of this + * CaptureDevice by looking for its MediaLocator is inefficient. + */ + @SuppressWarnings("unchecked") + Vector captureDeviceInfos + = (Vector) + CaptureDeviceManager.getDeviceList(null); + MediaLocator locator = captureDevice.getLocator(); + + for (CaptureDeviceInfo captureDeviceInfo : captureDeviceInfos) + if (captureDeviceInfo.getLocator().equals(locator)) + return captureDeviceInfo; + return null; + } + + /** + * Gets the content type of the media represented by this instance. The + * AbstractPushBufferCaptureDevice implementation always returns + * {@link ContentDescriptor#RAW}. + * + * @return the content type of the media represented by this instance + */ + public String getContentType() + { + return ContentDescriptor.RAW; + } + + /** + * Gets the control of the specified type available for this instance. + * + * @param controlType the type of the control available for this instance to + * be retrieved + * @return an Object which represents the control of the specified + * type available for this instance if such a control is indeed available; + * otherwise, null + */ + public Object getControl(String controlType) + { + return AbstractControls.getControl(this, controlType); + } + + /** + * Implements {@link Controls#getControls()}. Gets the controls available + * for this instance. + * + * @return an array of Objects which represent the controls + * available for this instance + */ + public Object[] getControls() + { + FormatControl[] formatControls = internalGetFormatControls(); + + if ((formatControls == null) || (formatControls.length == 0)) + return ControlsAdapter.EMPTY_CONTROLS; + else + { + Object[] controls = new Object[formatControls.length]; + + System.arraycopy( + formatControls, + 0, + controls, + 0, + formatControls.length); + return controls; + } + } + + /** + * Gets the duration of the media represented by this instance. The + * AbstractPushBufferCaptureDevice always returns + * {@link #DURATION_UNBOUNDED}. + * + * @return the duration of the media represented by this instance + */ + public Time getDuration() + { + return DURATION_UNBOUNDED; + } + + /** + * Gets the Format which is to be reported by a specific + * FormatControl for a PushBufferStream at a specific + * zero-based index in the list of streams of this + * PushBufferDataSource. + * + * @param streamIndex the zero-based index of the PushBufferStream + * in the list of streams of this PushBufferDataSource for which + * the specified FormatControl is to report a Format + * @param formatControl the FormatControl which si to report the + * Format + * @return the Format which is to be reported by + * formatControl as the format of the PushBufferStream at + * the specified streamIndex in the list of streams of this + * PushBufferDataSource + */ + protected Format getFormat(int streamIndex, FormatControl formatControl) + { + Format[] supportedFormats + = getSupportedFormats(streamIndex, formatControl); + + return + ((supportedFormats == null) || (supportedFormats.length < 1)) + ? null + : supportedFormats[0]; + } + + /** + * Gets an array of FormatControl instances each one of which can + * be used before {@link #connect()} to get and set the capture + * Format of each one of the capture streams. + * + * @return an array of FormatControl instances each one of which + * can be used before {@link #connect()} to get and set the capture + * Format of each one of the capture streams + */ + public FormatControl[] getFormatControls() + { + return AbstractFormatControl.getFormatControls(this); + } + + /** + * Gets the PushBufferStreams through which this + * PushBufferDataSource gives access to its media data. + * + * @return an array of the PushBufferStreams through which this + * PushBufferDataSource gives access to its media data + */ + public synchronized PushBufferStream[] getStreams() + { + if (streams == null) + { + FormatControl[] formatControls = internalGetFormatControls(); + + if (formatControls != null) + { + int formatControlCount = formatControls.length; + + streams = new AbstractPushBufferStream[formatControlCount]; + for (int i = 0; i < formatControlCount; i++) + streams[i] = createStream(i, formatControls[i]); + + /* + * Start the streams if this DataSource has already been + * started. + */ + if (started) + for (AbstractPushBufferStream stream : streams) + try + { + stream.start(); + } + catch (IOException ioex) + { + throw new UndeclaredThrowableException(ioex); + } + } + } + if (streams == null) + return EMPTY_STREAMS; + else + { + PushBufferStream[] clone = new PushBufferStream[streams.length]; + + System.arraycopy(streams, 0, clone, 0, streams.length); + return clone; + } + } + + /** + * Gets the Formats which are to be reported by a specific + * FormatControl as supported formats for a + * PushBufferStream at a specific zero-based index in the list of + * streams of this PushBufferDataSource. + * + * @param streamIndex the zero-based index of the PushBufferStream + * for which the specified FormatControl is to report the list of + * supported Formats + * @param formatControl the FormatControl which is to reports a + * list of supported Formats + * @return an array of Formats to be reported by + * formatControl as the supported formats for the + * PushBufferStream at the specified streamIndex in the + * list of streams of this PushBufferDataSource + */ + protected Format[] getSupportedFormats( + int streamIndex, + FormatControl formatControl) + { + CaptureDeviceInfo captureDeviceInfo = getCaptureDeviceInfo(); + + return + (captureDeviceInfo == null) ? null : captureDeviceInfo.getFormats(); + } + + /** + * Gets an array of FormatControl instances each one of which can + * be used before {@link #connect()} to get and set the capture + * Format of each one of the capture streams. + * + * @return an array of FormatControl instances each one of which + * can be used before {@link #connect()} to get and set the capture + * Format of each one of the capture streams + */ + private synchronized FormatControl[] internalGetFormatControls() + { + if (formatControls == null) + formatControls = createFormatControls(); + return formatControls; + } + + /** + * Starts the transfer of media data from this DataSource + * + * @throws IOException if anything goes wrong while starting the transfer of + * media data from this DataSource + */ + public synchronized void start() + throws IOException + { + if (!started) + { + if (!connected) + throw + new IOException( + getClass().getSimpleName() + " not connected"); + + doStart(); + started = true; + } + } + + /** + * Stops the transfer of media data from this DataSource. + * + * @throws IOException if anything goes wrong while stopping the transfer of + * media data from this DataSource + */ + public synchronized void stop() + throws IOException + { + if (started) + { + doStop(); + started = false; + } + } +} diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/AbstractPushBufferStream.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/AbstractPushBufferStream.java index 2321173bb..d4a92c8fb 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/AbstractPushBufferStream.java +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/AbstractPushBufferStream.java @@ -6,9 +6,14 @@ */ package net.java.sip.communicator.impl.neomedia.jmfext.media.protocol; +import java.io.*; + +import javax.media.*; +import javax.media.control.*; import javax.media.protocol.*; import net.java.sip.communicator.impl.neomedia.control.*; +import net.java.sip.communicator.util.*; /** * Provides a base implementation of PushBufferStream in order to @@ -18,10 +23,17 @@ * @author Lubomir Marinov */ public abstract class AbstractPushBufferStream - extends ControlsAdapter + extends AbstractControls implements PushBufferStream { + /** + * The Logger used by the AbstractPushBufferStream class + * and its instances for logging output. + */ + private static final Logger logger + = Logger.getLogger(AbstractPushBufferStream.class); + /** * The (default) ContentDescriptor of the * AbstractPushBufferStream instances. @@ -29,12 +41,49 @@ public abstract class AbstractPushBufferStream private static final ContentDescriptor CONTENT_DESCRIPTOR = new ContentDescriptor(ContentDescriptor.RAW); + /** + * The FormatControl which gives access to the Format of + * the media data provided by this SourceStream and which, + * optionally, allows setting it. + */ + private final FormatControl formatControl; + /** * The BufferTransferHandler which is notified by this * PushBufferStream when data is available for reading. */ protected BufferTransferHandler transferHandler; + /** + * Initializes a new AbstractPushBufferStream instance which is to + * have its Format-related information abstracted by a specific + * FormatControl. + * + * @param formatControl the FormatControl which is to abstract the + * Format-related information of the new instance + */ + protected AbstractPushBufferStream(FormatControl formatControl) + { + this.formatControl = formatControl; + } + + /** + * Releases the resources used by this instance throughout its existence and + * makes it available for garbage collection. This instance is considered + * unusable after closing. + */ + public void close() + { + try + { + stop(); + } + catch (IOException ioex) + { + logger.error("Failed to stop " + getClass().getSimpleName(), ioex); + } + } + /** * Determines whether the end of this SourceStream has been * reached. The AbstractPushBufferStream implementation always @@ -76,6 +125,33 @@ public long getContentLength() return LENGTH_UNKNOWN; } + /** + * Implements {@link Controls#getControls()}. Gets the controls available + * for this instance. + * + * @return an array of Objects which represent the controls + * available for this instance + */ + public Object[] getControls() + { + if (formatControl != null) + return new Object[] { formatControl }; + else + return ControlsAdapter.EMPTY_CONTROLS; + } + + /** + * Gets the Format of the media data made available by this + * PushBufferStream. + * + * @return the Format of the media data made available by this + * PushBufferStream + */ + public Format getFormat() + { + return (formatControl == null) ? null : formatControl.getFormat(); + } + /** * Sets the BufferTransferHandler which is to be notified by this * PushBufferStream when data is available for reading. @@ -88,4 +164,22 @@ public void setTransferHandler(BufferTransferHandler transferHandler) { this.transferHandler = transferHandler; } + + /** + * Starts the transfer of media data from this PushBufferStream. + * + * @throws IOException if anything goes wrong while starting the transfer of + * media data from this PushBufferStream + */ + public abstract void start() + throws IOException; + + /** + * Stops the transfer of media data from this PushBufferStream. + * + * @throws IOException if anything goes wrong while stopping the transfer of + * media data from this PushBufferStream + */ + public abstract void stop() + throws IOException; } diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/DataSource.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/DataSource.java index 06f4b9a88..10058ca60 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/DataSource.java +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/DataSource.java @@ -7,15 +7,12 @@ package net.java.sip.communicator.impl.neomedia.jmfext.media.protocol.imgstreaming; import java.awt.*; -import java.io.*; import javax.media.*; -import javax.media.format.*; -import javax.media.protocol.*; import javax.media.control.*; +import javax.media.format.*; -import net.java.sip.communicator.impl.neomedia.control.*; -import net.java.sip.communicator.util.*; +import net.java.sip.communicator.impl.neomedia.jmfext.media.protocol.*; /** * DataSource for our image streaming (which is used for @@ -26,61 +23,27 @@ * @author Damian Minkov */ public class DataSource - extends PushBufferDataSource - implements CaptureDevice + extends AbstractPushBufferCaptureDevice { - /** - * The Logger. - */ - private static final Logger logger = Logger.getLogger(DataSource.class); /** - * DataSource connection state. - */ - private boolean connected = false; - - /** - * DataSource start state. - */ - private boolean started = false; - - /** - * The JMF controls (which are likely of type Control) available - * for this DataSource. - */ - private final Object[] controls = { new FormatControlImpl() }; - - /** - * Image stream. - */ - private ImageStream stream = null; - - /** - * The value of the streams property of DataSource which - * represents an empty array of PushBufferStreams i.e. no - * ImageStreams in DataSource. Explicitly defined in - * order to reduce unnecessary allocations. + * Array of supported formats. */ - private static final PushBufferStream[] EMPTY_STREAMS = - new PushBufferStream[0]; + private static final Format formats[]; /** - * Resolution supported for image. + * Resolutions supported for image. Listed in decreasing order of + * preference. */ private static final Dimension res[] = new Dimension[] { - new Dimension(128,96), - new Dimension(176, 144), - new Dimension(320, 240), - new Dimension(352, 288), - new Dimension(704, 576), new Dimension(720, 480), + new Dimension(704, 576), + new Dimension(352, 288), + new Dimension(320, 240), + new Dimension(176, 144), + new Dimension(128,96), }; - /** - * Array of supported formats. - */ - private static final Format formats[]; - static { /* initialize supported format array */ @@ -103,23 +66,6 @@ public class DataSource } } - /** - * Constructor. - */ - public DataSource() - { - } - - /** - * Constructor. - * - * @param locator associated MediaLocator - */ - public DataSource(MediaLocator locator) - { - setLocator(locator); - } - /** * Get supported formats. * @@ -131,202 +77,43 @@ public static Format[] getFormats() } /** - * Get the JMF streams. - * - * @return streams (one element in image streaming case) - */ - public PushBufferStream[] getStreams() - { - if(stream == null) - { - stream = new ImageStream(getLocator()); - /* XXX allow to select other format */ - stream.setFormat(getFormats()[5]); - } - - return (stream == null) ? EMPTY_STREAMS : - new PushBufferStream[] {stream}; - } - - /** - * Initialize DataSource. - * - * @throws IOException if initialization problem occurred - */ - public void connect() throws IOException - { - if(connected) - { - return; - } - - connected = true; - } - - /** - * Disconnect datasource. - */ - public void disconnect() - { - connected = false; - } - - /** - * Get content type. - * - * @return RAW content type - */ - public String getContentType() - { - return ContentDescriptor.RAW; - } - - /** - * Get duration for this source which is unknown. - * - * @return DURATION_UNKNOWN - */ - public Time getDuration() - { - return DURATION_UNKNOWN; - } - - /** - * Gives control information to the caller. - * - * @return the collection of object controls. - */ - public Object[] getControls() - { - /* - * The field controls is private so we cannot directly return it. - * Otherwise, the caller will be able to modify it. - */ - return controls.clone(); - } - - /** - * Return required control from the Control[] array - * if exists. - * - * @param controlType the control we are interested in. - * @return the object that implements the control, or null if not found - */ - public Object getControl(String controlType) - { - return AbstractControls.getControl(this, controlType); - } - - /** - * Get the CaptureDeviceInfo associated - * with this datasource. - * - * @return CaptureDeviceInfo associated - */ - public CaptureDeviceInfo getCaptureDeviceInfo() - { - MediaLocator locator = getLocator(); - - return - new CaptureDeviceInfo( - locator.getRemainder(), - locator, - getFormatControls()[0].getSupportedFormats()); - } - - /** - * Get supported FormatControl. - * - * @return array of supported FormatControl + * Constructor. */ - public FormatControl[] getFormatControls() + public DataSource() { - return AbstractFormatControl.getFormatControls(this); } /** - * Start capture. + * Constructor. * - * @throws IOException - */ - public void start() throws IOException - { - /* DataSource already started, do not care */ - if(started) - { - return; - } - - if(!connected) - { - throw new IOException("DataSource must be connected!"); - } - - stream.start(); - started = true; - } - - /** - * Stop capture. + * @param locator associated MediaLocator */ - public void stop() + public DataSource(MediaLocator locator) { - if(started) - { - started = false; - stream.stop(); - } + super(locator); } /** - * Implementation of FormatControl for this DataSource instance. + * Create a new PushBufferStream which is to be at a specific + * zero-based index in the list of streams of this + * PushBufferDataSource. The Format-related information of + * the new instance is to be abstracted by a specific + * FormatControl. * - * @author Sebastien Vincent - */ - private class FormatControlImpl - extends AbstractFormatControl - { - /** - * Current format used. - */ - private Format format = formats[0]; - - /** - * Set the format used. - * - * @param format format to use - * @return format used or null if format is not supported - */ - @Override - public Format setFormat(Format format) - { - Format f = AbstractFormatControl.setFormat(this, format); - - if(f != null) - this.format = f; - return f; - } - - /** - * Get current format used. - * - * @return the Format of this DataSource - */ - public Format getFormat() - { - return format; - } - - /** - * Get supported formats. - * - * @return an array of Format element type which lists the JMF - * formats supported by this DataSource i.e. the ones in which - * it is able to output - */ - public Format[] getSupportedFormats() - { - return formats.clone(); - } + * @param streamIndex the zero-based index of the PushBufferStream + * in the list of streams of this PushBufferDataSource + * @param formatControl the FormatControl which is to abstract the + * Format-related information of the new instance + * @return a new PushBufferStream which is to be at the specified + * streamIndex in the list of streams of this + * PushBufferDataSource and which has its Format-related + * information abstracted by the specified formatControl + * @see AbstractPushBufferCaptureDevice#createStream(int, FormatControl) + */ + protected AbstractPushBufferStream createStream( + int streamIndex, + FormatControl formatControl) + { + return new ImageStream(formatControl); } } diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java index 129db083b..6f9086f02 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java @@ -11,6 +11,7 @@ import java.io.*; import javax.media.*; +import javax.media.control.*; import javax.media.format.*; import javax.media.protocol.*; @@ -36,11 +37,6 @@ public class ImageStream */ private static final Logger logger = Logger.getLogger(ImageStream.class); - /** - * Current format used. - */ - private Format currentFormat = null; - /** * Sequence number. */ @@ -67,39 +63,15 @@ public class ImageStream private DesktopInteract desktopInteract = null; /** - * Constructor. - */ - public ImageStream() - { - } - - /** - * Constructor. + * Initializes a new ImageStream instance which is to have a + * specific FormatControl * - * @param locator MediaLocator to use + * @param formatControl the FormatControl of the new instance which + * is to specify the format in which it is to provide its media data */ - public ImageStream(MediaLocator locator) + ImageStream(FormatControl formatControl) { - } - - /** - * Set format to use. - * - * @param format new format to use - */ - public void setFormat(Format format) - { - currentFormat = format; - } - - /** - * Returns the supported format by this stream. - * - * @return supported formats - */ - public Format getFormat() - { - return currentFormat; + super(formatControl); } /** @@ -142,6 +114,8 @@ public void read(Buffer buffer) /** * Start desktop capture stream. + * + * @see AbstractPushBufferStream#start() */ public void start() { @@ -149,13 +123,21 @@ public void start() { logger.info("Start stream"); captureThread = new Thread(this); - captureThread.start(); + + /* + * Set the started indicator before calling Thread#start() because + * the Thread may exist upon start if Thread#run() starts executing + * before setting the started indicator. + */ started = true; + captureThread.start(); } } /** * Stop desktop capture stream. + * + * @see AbstractPushBufferStream#stop() */ public void stop() { @@ -169,7 +151,7 @@ public void stop() */ public void run() { - final RGBFormat format = (RGBFormat)currentFormat; + final RGBFormat format = (RGBFormat) getFormat(); Dimension formatSize = format.getSize(); final int width = (int)formatSize.getWidth(); final int height = (int)formatSize.getHeight(); @@ -208,7 +190,7 @@ public void run() buf.setData(data); buf.setOffset(0); buf.setLength(data.length); - buf.setFormat(currentFormat); + buf.setFormat(format); buf.setHeader(null); buf.setTimeStamp(System.nanoTime()); buf.setSequenceNumber(seqNo++); diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java index 5bce0a5f9..5160dd902 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java @@ -7,7 +7,6 @@ package net.java.sip.communicator.impl.neomedia.jmfext.media.protocol.portaudio; import java.io.*; -import java.util.*; import javax.media.*; import javax.media.control.*; @@ -16,6 +15,7 @@ import net.java.sip.communicator.impl.neomedia.*; import net.java.sip.communicator.impl.neomedia.control.*; +import net.java.sip.communicator.impl.neomedia.jmfext.media.protocol.*; import net.java.sip.communicator.impl.neomedia.portaudio.*; import net.java.sip.communicator.util.*; @@ -144,20 +144,7 @@ public synchronized void disconnect() */ public CaptureDeviceInfo getCaptureDeviceInfo() { - /* - * TODO The implemented search for the CaptureDeviceInfo of this - * CaptureDevice by looking for its MediaLocator is inefficient. - */ - @SuppressWarnings("unchecked") - Vector captureDeviceInfos - = (Vector) - CaptureDeviceManager.getDeviceList(null); - MediaLocator locator = getLocator(); - - for (CaptureDeviceInfo captureDeviceInfo : captureDeviceInfos) - if (captureDeviceInfo.getLocator().equals(locator)) - return captureDeviceInfo; - return null; + return AbstractPushBufferCaptureDevice.getCaptureDeviceInfo(this); } /**