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

org.jitsi.impl.neomedia.device.MediaDeviceImpl Maven / Gradle / Ivy

Go to download

libjitsi is an advanced Java media library for secure real-time audio/video communication

The newest version!
/*
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jitsi.impl.neomedia.device;

import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.List;

import javax.media.*;
import javax.media.control.*;
import javax.media.protocol.*;

import org.jitsi.impl.neomedia.*;
import org.jitsi.impl.neomedia.format.*;
import org.jitsi.impl.neomedia.jmfext.media.protocol.*;
import org.jitsi.impl.neomedia.protocol.*;
import org.jitsi.service.neomedia.*;
import org.jitsi.service.neomedia.codec.*;
import org.jitsi.service.neomedia.device.*;
import org.jitsi.service.neomedia.format.*;
import org.jitsi.utils.*;
import org.jitsi.utils.logging.*;

/**
 * Implements MediaDevice for the JMF CaptureDevice.
 *
 * @author Lyubomir Marinov
 * @author Emil Ivov
 */
public class MediaDeviceImpl
    extends AbstractMediaDevice
{

    /**
     * The Logger used by MediaDeviceImpl and its instances
     * for logging output.
     */
    private static final Logger logger
        = Logger.getLogger(MediaDeviceImpl.class);

    /**
     * Creates a new CaptureDevice which traces calls to a specific
     * CaptureDevice for debugging purposes.
     *
     * @param captureDevice the CaptureDevice which is to have its
     * calls traced for debugging output
     * @param logger the Logger to be used for logging the trace
     * messages
     * @return a new CaptureDevice which traces the calls to the
     * specified captureDevice
     */
    public static CaptureDevice createTracingCaptureDevice(
            CaptureDevice captureDevice,
            final Logger logger)
    {
        if (captureDevice instanceof PushBufferDataSource)
            captureDevice
                = new CaptureDeviceDelegatePushBufferDataSource(
                        captureDevice)
                {
                    @Override
                    public void connect()
                        throws IOException
                    {
                        super.connect();

                        if (logger.isTraceEnabled())
                            logger
                                .trace(
                                    "Connected "
                                        + MediaDeviceImpl
                                            .toString(this.captureDevice));
                    }

                    @Override
                    public void disconnect()
                    {
                        super.disconnect();

                        if (logger.isTraceEnabled())
                            logger
                                .trace(
                                    "Disconnected "
                                        + MediaDeviceImpl
                                            .toString(this.captureDevice));
                    }

                    @Override
                    public void start()
                        throws IOException
                    {
                        super.start();

                        if (logger.isTraceEnabled())
                            logger
                                .trace(
                                    "Started "
                                        + MediaDeviceImpl
                                            .toString(this.captureDevice));
                    }

                    @Override
                    public void stop()
                        throws IOException
                    {
                        super.stop();

                        if (logger.isTraceEnabled())
                            logger
                                .trace(
                                    "Stopped "
                                        + MediaDeviceImpl
                                            .toString(this.captureDevice));
                    }
                };
        return captureDevice;
    }

    /**
     * Returns a human-readable representation of a specific
     * CaptureDevice in the form of a String value.
     *
     * @param captureDevice the CaptureDevice to get a human-readable
     * representation of
     * @return a String value which gives a human-readable
     * representation of the specified captureDevice
     */
    private static String toString(CaptureDevice captureDevice)
    {
        StringBuffer str = new StringBuffer();

        str.append("CaptureDevice with hashCode ");
        str.append(captureDevice.hashCode());
        str.append(" and captureDeviceInfo ");

        CaptureDeviceInfo captureDeviceInfo
            = captureDevice.getCaptureDeviceInfo();

        MediaLocator mediaLocator = null;
        if (captureDeviceInfo != null)
        {
            mediaLocator = captureDeviceInfo.getLocator();
        }

        str.append((mediaLocator == null) ? captureDeviceInfo : mediaLocator);
        return str.toString();
    }

    /**
     * The CaptureDeviceInfo of the device that this instance is
     * representing.
     */
    private final CaptureDeviceInfo captureDeviceInfo;

    /**
     * The MediaType of this instance and the CaptureDevice
     * that it wraps.
     */
    private final MediaType mediaType;

    /**
     * Initializes a new MediaDeviceImpl instance which is to provide
     * an implementation of MediaDevice for a CaptureDevice
     * with a specific CaptureDeviceInfo and which is of a specific
     * MediaType.
     *
     * @param captureDeviceInfo the CaptureDeviceInfo of the JMF
     * CaptureDevice the new instance is to provide an implementation
     * of MediaDevice for
     * @param mediaType the MediaType of the new instance
     */
    public MediaDeviceImpl(
            CaptureDeviceInfo captureDeviceInfo,
            MediaType mediaType)
    {
        if (captureDeviceInfo == null)
            throw new NullPointerException("captureDeviceInfo");
        if (mediaType == null)
            throw new NullPointerException("mediaType");

        this.captureDeviceInfo = captureDeviceInfo;
        this.mediaType = mediaType;
    }

    /**
     * Initializes a new MediaDeviceImpl instance with a specific
     * MediaType and with MediaDirection which does not allow
     * sending.
     *
     * @param mediaType the MediaType of the new instance
     */
    public MediaDeviceImpl(MediaType mediaType)
    {
        this.captureDeviceInfo = null;
        this.mediaType = mediaType;
    }

    /**
     * Creates the JMF CaptureDevice this instance represents and
     * provides an implementation of MediaDevice for.
     *
     * @return the JMF CaptureDevice this instance represents and
     * provides an implementation of MediaDevice for; null
     * if the creation fails
     */
    protected CaptureDevice createCaptureDevice()
    {
        CaptureDevice captureDevice = null;

        if (getDirection().allowsSending())
        {
            CaptureDeviceInfo captureDeviceInfo = getCaptureDeviceInfo();
            Throwable exception = null;

            try
            {
                captureDevice
                    = (CaptureDevice)
                        Manager.createDataSource(
                                captureDeviceInfo.getLocator());
            }
            catch (IOException ioe)
            {
                exception = ioe;
            }
            catch (NoDataSourceException ndse)
            {
                exception = ndse;
            }

            if (exception != null)
            {
                logger.error(
                        "Failed to create CaptureDevice"
                            + " from CaptureDeviceInfo "
                            + captureDeviceInfo,
                        exception);
            }
            else
            {
                if (captureDevice instanceof AbstractPullBufferCaptureDevice)
                {
                    ((AbstractPullBufferCaptureDevice) captureDevice)
                        .setCaptureDeviceInfo(captureDeviceInfo);
                }

                // Try to enable tracing on captureDevice.
                if (logger.isTraceEnabled())
                {
                    captureDevice
                        = createTracingCaptureDevice(captureDevice, logger);
                }
            }
        }
        return captureDevice;
    }

    /**
     * Creates a DataSource instance for this MediaDevice
     * which gives access to the captured media.
     *
     * @return a DataSource instance which gives access to the media
     * captured by this MediaDevice
     * @see AbstractMediaDevice#createOutputDataSource()
     */
    @Override
    protected DataSource createOutputDataSource()
    {
        return
            getDirection().allowsSending()
                ? (DataSource) createCaptureDevice()
                : null;
    }

    /**
     * Gets the CaptureDeviceInfo of the JMF CaptureDevice
     * represented by this instance.
     *
     * @return the CaptureDeviceInfo of the CaptureDevice
     * represented by this instance
     */
    public CaptureDeviceInfo getCaptureDeviceInfo()
    {
        return captureDeviceInfo;
    }

    /**
     * Gets the protocol of the MediaLocator of the
     * CaptureDeviceInfo represented by this instance.
     *
     * @return the protocol of the MediaLocator of the
     * CaptureDeviceInfo represented by this instance
     */
    public String getCaptureDeviceInfoLocatorProtocol()
    {
        CaptureDeviceInfo cdi = getCaptureDeviceInfo();

        if (cdi != null)
        {
            MediaLocator locator = cdi.getLocator();

            if (locator != null)
                return locator.getProtocol();
        }

        return null;
    }

    /**
     * Returns the MediaDirection supported by this device.
     *
     * @return {@link MediaDirection#SENDONLY} if this is a read-only device,
     * {@link MediaDirection#RECVONLY} if this is a write-only device or
     * {@link MediaDirection#SENDRECV} if this MediaDevice can both
     * capture and render media
     * @see MediaDevice#getDirection()
     */
    public MediaDirection getDirection()
    {
        if (getCaptureDeviceInfo() != null)
            return MediaDirection.SENDRECV;
        else
            return
                MediaType.AUDIO.equals(getMediaType())
                    ? MediaDirection.INACTIVE
                    : MediaDirection.RECVONLY;
    }

    /**
     * Gets the MediaFormat in which this MediaDevice captures
     * media.
     *
     * @return the MediaFormat in which this MediaDevice
     * captures media
     * @see MediaDevice#getFormat()
     */
    public MediaFormat getFormat()
    {
        CaptureDevice captureDevice = createCaptureDevice();

        if (captureDevice != null)
        {
            MediaType mediaType = getMediaType();

            for (FormatControl formatControl
                    : captureDevice.getFormatControls())
            {
                MediaFormat format
                    = MediaFormatImpl.createInstance(formatControl.getFormat());

                if ((format != null) && format.getMediaType().equals(mediaType))
                    return format;
            }
        }
        return null;
    }

    /**
     * Gets the MediaType that this device supports.
     *
     * @return {@link MediaType#AUDIO} if this is an audio device or
     * {@link MediaType#VIDEO} if this is a video device
     * @see MediaDevice#getMediaType()
     */
    public MediaType getMediaType()
    {
        return mediaType;
    }

    /**
     * Gets the list of MediaFormats supported by this
     * MediaDevice and enabled in encodingConfiguration.
     *
     * @param encodingConfiguration the EncodingConfiguration instance
     * to use
     * @return the list of MediaFormats supported by this device
     * and enabled in encodingConfiguration.
     * @see MediaDevice#getSupportedFormats()
     */
    public List getSupportedFormats(
            EncodingConfiguration encodingConfiguration)
    {
        return getSupportedFormats(null, null, encodingConfiguration);
    }

    /**
     * Gets the list of MediaFormats supported by this
     * MediaDevice. Uses the current EncodingConfiguration
     * from the media service (i.e. the global configuration).
     *
     * @param sendPreset the preset used to set some of the format parameters,
     * used for video and settings.
     * @param receivePreset the preset used to set the receive format
     * parameters, used for video and settings.
     * @return the list of MediaFormats supported by this device
     * @see MediaDevice#getSupportedFormats()
     */
    public List getSupportedFormats(
            QualityPreset sendPreset,
            QualityPreset receivePreset)
    {
        return
            getSupportedFormats(
                    sendPreset,
                    receivePreset,
                    NeomediaServiceUtils.getMediaServiceImpl()
                            .getCurrentEncodingConfiguration());
    }

    /**
     * Gets the list of MediaFormats supported by this
     * MediaDevice and enabled in encodingConfiguration.
     *
     * @param sendPreset the preset used to set some of the format parameters,
     * used for video and settings.
     * @param receivePreset the preset used to set the receive format
     * parameters, used for video and settings.
     * @param encodingConfiguration the EncodingConfiguration instance
     * to use
     * @return the list of MediaFormats supported by this device
     * and enabled in encodingConfiguration.
     * @see MediaDevice#getSupportedFormats()
     */
    public List getSupportedFormats(
            QualityPreset sendPreset,
            QualityPreset receivePreset,
            EncodingConfiguration encodingConfiguration)
    {
        MediaServiceImpl mediaServiceImpl
            = NeomediaServiceUtils.getMediaServiceImpl();
        MediaFormat[] enabledEncodings
            = encodingConfiguration.getEnabledEncodings(getMediaType());
        List supportedFormats = new ArrayList();

        // If there is preset, check and set the format attributes where needed.
        if (enabledEncodings != null)
        {
            for (MediaFormat f : enabledEncodings)
            {
                if("h264".equalsIgnoreCase(f.getEncoding()))
                {
                    Map advancedAttrs
                        = f.getAdvancedAttributes();

                    CaptureDeviceInfo captureDeviceInfo
                        = getCaptureDeviceInfo();
                    MediaLocator captureDeviceInfoLocator;
                    Dimension sendSize = null;

                    // change send size only for video calls
                    if ((captureDeviceInfo != null)
                            && ((captureDeviceInfoLocator
                                        = captureDeviceInfo.getLocator())
                                    != null)
                            && !DeviceSystem.LOCATOR_PROTOCOL_IMGSTREAMING
                                .equals(captureDeviceInfoLocator.getProtocol()))
                    {
                        if (sendPreset != null)
                            sendSize = sendPreset.getResolution();
                        else
                        {
                            /*
                             * XXX We cannot default to any video size here
                             * because we do not know how this MediaDevice
                             * instance will be used. If the caller wanted to
                             * limit the video size, she would've specified an
                             * actual sendPreset.
                             */
//                            sendSize
//                                = mediaServiceImpl
//                                    .getDeviceConfiguration()
//                                        .getVideoSize();
                        }
                    }

                    Dimension receiveSize;

                    // if there is specified preset, send its settings
                    if (receivePreset != null)
                        receiveSize = receivePreset.getResolution();
                    else
                    {
                        // or just send the max video resolution of the PC as we
                        // do by default
                        ScreenDevice screen
                            = mediaServiceImpl.getDefaultScreenDevice();

                        receiveSize
                            = (screen == null) ? null : screen.getSize();
                    }

                    advancedAttrs.put(
                            "imageattr",
                            MediaUtils.createImageAttr(sendSize, receiveSize));
                    f
                        = mediaServiceImpl.getFormatFactory().createMediaFormat(
                                f.getEncoding(),
                                f.getClockRate(),
                                f.getFormatParameters(),
                                advancedAttrs);
                }

                if (f != null)
                    supportedFormats.add(f);
            }
        }

        return supportedFormats;
    }

    /**
     * Gets a human-readable String representation of this instance.
     *
     * @return a String providing a human-readable representation of
     * this instance
     */
    @Override
    public String toString()
    {
        CaptureDeviceInfo captureDeviceInfo = getCaptureDeviceInfo();

        return
            (captureDeviceInfo == null)
                ? super.toString()
                : captureDeviceInfo.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy