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

org.jitsi.service.neomedia.codec.EncodingConfiguration 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.service.neomedia.codec;

import java.util.*;

import org.jitsi.service.neomedia.format.*;
import org.jitsi.utils.*;
import org.jitsi.utils.logging.*;

/**
 * A base class that manages encoding configurations. It holds information
 * about supported formats.
 *
 * @author Damian Minkov
 * @author Lyubomir Marinov
 * @author Boris Grozev
 */
public abstract class EncodingConfiguration
{
    /**
     * The Logger used by this EncodingConfiguration instance
     * for logging output.
     */
    private final Logger logger
        = Logger.getLogger(EncodingConfiguration.class);

    /**
     * The Comparator which sorts the sets according to the settings in
     * encodingPreferences.
     */
    private final Comparator encodingComparator
        = new Comparator()
                {
                    public int compare(MediaFormat s1, MediaFormat s2)
                    {
                        return compareEncodingPreferences(s1, s2);
                    }
                };

    /**
     * That's where we keep format preferences matching SDP formats to integers.
     * We keep preferences for both audio and video formats here in case we'd
     * ever need to compare them to one another. In most cases however both
     * would be decorelated and other components (such as the UI) should present
     * them separately.
     */
    protected final Map encodingPreferences
        = new HashMap();

    /**
     * The cache of supported AudioMediaFormats ordered by decreasing
     * priority.
     */
    private Set supportedAudioEncodings;

    /**
     * The cache of supported VideoMediaFormats ordered by decreasing
     * priority.
     */
    private Set supportedVideoEncodings;

    /**
     * Updates the codecs in the supported sets according to the preferences in
     * encodingPreferences. If the preference value is 0, the codec is
     * disabled.
     */
    private void updateSupportedEncodings()
    {
        /*
         * If they need updating, their caches are invalid and need rebuilding
         * next time they are requested.
         */
        supportedAudioEncodings = null;
        supportedVideoEncodings = null;
    }

    /**
     * Gets the Set of enabled available MediaFormats with the
     * specified MediaType sorted in decreasing priority.
     *
     * @param type the MediaType of the MediaFormats to get
     * @return a Set of enabled available MediaFormats with
     * the specified MediaType sorted in decreasing priority
     */
    private Set updateSupportedEncodings(MediaType type)
    {
        Set enabled
            = new TreeSet(encodingComparator);

        for (MediaFormat format : getAllEncodings(type))
        {
            if (getPriority(format) > 0)
                enabled.add(format);
        }
        return enabled;
    }

    /**
     * Sets pref as the preference associated with encoding.
     * Use this method for both audio and video encodings and don't worry if
     * preferences are equal since we rarely need to compare prefs of video
     * encodings to those of audio encodings.
     *
     * @param encoding the SDP int of the encoding whose pref we're setting.
     * @param clockRate clock rate
     * @param pref a positive int indicating the preference for that encoding.
     */
    protected abstract void setEncodingPreference(
            String encoding, double clockRate,
            int pref);

    /**
     * Sets priority as the preference associated with
     * encoding. Use this method for both audio and video encodings and
     * don't worry if the preferences are equal since we rarely need to compare
     * the preferences of video encodings to those of audio encodings.
     *
     * @param encoding the MediaFormat specifying the encoding to set
     * the priority of
     * @param priority a positive int indicating the priority of
     * encoding to set
     */
    public void setPriority(MediaFormat encoding, int priority)
    {
        String encodingEncoding = encoding.getEncoding();

        /*
         * Since we'll be remembering the priority in the ConfigurationService
         * by associating it with a property name/key based on encoding and
         * clock rate only, it does not make sense to store the MediaFormat in
         * encodingPreferences because MediaFormat is much more specific than
         * just encoding and clock rate.
         */
        setEncodingPreference(
                encodingEncoding, encoding.getClockRate(),
                priority);

        updateSupportedEncodings();
    }

    /**
     * Get the priority for a MediaFormat.
     *
     * @param encoding the MediaFormat
     * @return the priority
     */
    public int getPriority(MediaFormat encoding)
    {
        /*
         * Directly returning encodingPreference.get(encoding) will throw a
         * NullPointerException if encodingPreferences does not contain a
         * mapping for encoding.
         */
        Integer priority
            = encodingPreferences.get(getEncodingPreferenceKey(encoding));

        return (priority == null) ? 0 : priority;
    }

    /**
     * Returns all the available encodings for a specific MediaType.
     * This includes disabled ones (ones with priority 0).
     *
     * @param type the MediaType we would like to know the available
     * encodings of
     * @return array of MediaFormat supported for the
     * MediaType
     */
    public abstract MediaFormat[] getAllEncodings(MediaType type);

    /**
     * Returns the supported MediaFormats i.e. the enabled available
     * MediaFormats, sorted in decreasing priority. Returns only the
     * formats of type type.
     *
     * @param type the MediaType of the supported MediaFormats
     * to get
     * @return an array of the supported MediaFormats i.e. the enabled
     * available MediaFormats sorted in decreasing priority. Returns
     * only the formats of type type.
     */
    public MediaFormat[] getEnabledEncodings(MediaType type)
    {
        Set supportedEncodings;

        switch (type)
        {
        case AUDIO:
            if (supportedAudioEncodings == null)
                supportedAudioEncodings = updateSupportedEncodings(type);
            supportedEncodings = supportedAudioEncodings;
            break;
        case VIDEO:
            if (supportedVideoEncodings == null)
                supportedVideoEncodings = updateSupportedEncodings(type);
            supportedEncodings = supportedVideoEncodings;
            break;
        default:
            return new MediaFormat[0];
        }

        return
            supportedEncodings.toArray(
                    new MediaFormat[supportedEncodings.size()]);
    }

    /**
     * Compares the two formats for order. Returns a negative integer, zero, or
     * a positive integer as the first format has been assigned a preference
     * higher, equal to, or greater than the one of the second.
     *
     * @param enc1 the first format to compare for preference.
     * @param enc2 the second format to compare for preference
     * @return a negative integer, zero, or a positive integer as the first
     * format has been assigned a preference higher, equal to, or greater than
     * the one of the second
     */
    protected abstract
            int compareEncodingPreferences(MediaFormat enc1, MediaFormat enc2);


    /**
     * Gets the key in {@link #encodingPreferences} which is associated with the
     * priority of a specific MediaFormat.
     *
     * @param encoding the MediaFormat to get the key in
     * {@link #encodingPreferences} of
     * @return the key in {@link #encodingPreferences} which is associated with
     * the priority of the specified encoding
     */
    protected String getEncodingPreferenceKey(MediaFormat encoding)
    {
        return encoding.getEncoding() + "/" + encoding.getClockRateString();
    }

    /**
     * Stores the format preferences in this instance in the given Map,
     * using prefix as a prefix to the key.
     * Entries in the format (prefix+formatName, formatPriority) will be added
     * to properties, one for each available format.
     * Note that a "." is not automatically added to prefix.
     *
     * @param properties The Map where entries will be added.
     * @param prefix The prefix to use.
     */
    public void storeProperties(Map properties, String prefix)
    {
        for(MediaType mediaType : MediaType.values())
        {
            for(MediaFormat mediaFormat: getAllEncodings(mediaType))
            {
                properties.put(
                        prefix + getEncodingPreferenceKey(mediaFormat),
                        Integer.toString(getPriority(mediaFormat)));
            }
        }
    }

    /**
     * Stores the format preferences in this instance in the given Map.
     * Entries in the format (formatName, formatPriority) will be added to
     * properties, one for each available format.
     *
     * @param properties The Map where entries will be added.
     */
    public void storeProperties(Map properties)
    {
        storeProperties(properties, "");
    }

    /**
     * Parses a {@link Map} and updates the format preferences
     * according to it. Does not use a prefix.
     *
     * @param properties The Map to parse.
     *
     * @see EncodingConfiguration#loadProperties(java.util.Map, String)
     */
    public void loadProperties(Map properties)
    {
        loadProperties(properties, "");
    }

    /**
     * Parses a {@link Map} and updates the format preferences
     * according to it. For each entry, if it's key does not begin with
     * prefix, its ignored. If the key begins with prefix,
     * look for an encoding name after the last ".", and interpret the key
     * value as preference.
     *
     * @param properties The Map to parse.
     * @param prefix The prefix to use.
     */
    public void loadProperties(Map properties, String prefix)
    {
        for(Map.Entry entry : properties.entrySet())
        {
            String pName = entry.getKey();
            String prefStr = entry.getValue();
            String fmtName;

            if(!pName.startsWith(prefix))
                continue;

            if(pName.contains("."))
                fmtName = pName.substring(pName.lastIndexOf('.') + 1);
            else
                fmtName = pName;

            // legacy
            if (fmtName.contains("sdp"))
            {
                fmtName = fmtName.replaceAll("sdp", "");
                /*
                 * If the current version of the property name is also
                 * associated with a value, ignore the value for the legacy
                 * one.
                 */
                if (properties.containsKey(pName.replaceAll("sdp", "")))
                    continue;
            }

            int preference = -1;
            String encoding;
            double clockRate;

            try
            {
                preference = Integer.parseInt(prefStr);

                int encodingClockRateSeparator = fmtName.lastIndexOf('/');

                if (encodingClockRateSeparator > -1)
                {
                    encoding
                        = fmtName.substring(0, encodingClockRateSeparator);
                    clockRate
                        = Double.parseDouble(
                                fmtName.substring(
                                        encodingClockRateSeparator + 1));
                }
                else
                {
                    encoding = fmtName;
                    clockRate = MediaFormatFactory.CLOCK_RATE_NOT_SPECIFIED;
                }
            }
            catch (NumberFormatException nfe)
            {
                logger.warn(
                        "Failed to parse format ("
                            + fmtName
                            + ") or preference ("
                            + prefStr
                            + ").",
                        nfe);
                continue;
            }
            setEncodingPreference(encoding, clockRate, preference);
        }

        // now update the arrays so that they are returned by order of
        // preference.
        updateSupportedEncodings();
    }

    /**
     * Load the preferences stored in encodingConfiguration
     *
     * @param encodingConfiguration the EncodingConfiguration to load
     * preferences from.
     */
    public void loadEncodingConfiguration(
            EncodingConfiguration encodingConfiguration)
    {
        Map properties = new HashMap();

        encodingConfiguration.storeProperties(properties);
        loadProperties(properties);
    }

    /**
     * Returns true if there is at least one enabled format for media
     * type type.
     *
     * @param mediaType The media type, MediaType.AUDIO or MediaType.VIDEO
     * @return true if there is at least one enabled format for media
     * type type.
     */
    public boolean hasEnabledFormat(MediaType mediaType)
    {
        return (getEnabledEncodings(mediaType).length > 0);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy