From 70faddbcbc2bfa037cb353566b243fd1cf60e86e Mon Sep 17 00:00:00 2001
From: Emil Ivov <emcho@jitsi.org>
Date: Thu, 13 Sep 2012 15:40:15 +0000
Subject: [PATCH] Applies a patch from Boris Grozev that allows setting
 different codec configurations to different accounts. It is now possible to
 set entirely different codec preference for every account.

---
 .../jitsi/impl/neomedia/MediaServiceImpl.java |  11 +-
 src/org/jitsi/impl/neomedia/MediaUtils.java   |   2 +-
 .../codec/EncodingConfigurationImpl.java      | 434 +++++++++++++
 .../device/AudioMixerMediaDevice.java         |  22 +
 .../impl/neomedia/device/MediaDeviceImpl.java |  46 +-
 .../device/VideoTranslatorMediaDevice.java    |  27 +
 .../format/MediaFormatFactoryImpl.java        |   1 +
 .../neomedia/MediaConfigurationService.java   |  55 ++
 .../jitsi/service/neomedia/MediaService.java  |   6 +
 .../neomedia/codec/EncodingConfiguration.java | 607 +++++-------------
 .../service/neomedia/device/MediaDevice.java  |  21 +
 11 files changed, 783 insertions(+), 449 deletions(-)
 create mode 100644 src/org/jitsi/impl/neomedia/codec/EncodingConfigurationImpl.java
 create mode 100644 src/org/jitsi/service/neomedia/MediaConfigurationService.java
 rename src/org/jitsi/{impl => service}/neomedia/codec/EncodingConfiguration.java (50%)

diff --git a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java
index e7dbe022..73acc614 100644
--- a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java
+++ b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java
@@ -29,6 +29,7 @@
 import org.jitsi.service.configuration.*;
 import org.jitsi.service.libjitsi.*;
 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.service.resources.*;
@@ -144,7 +145,7 @@ public void propertyChange(PropertyChangeEvent event)
      * and the order of their preference.
      */
     private final EncodingConfiguration encodingConfiguration
-        = new EncodingConfiguration();
+        = new EncodingConfigurationImpl();
 
     /**
      * The <tt>MediaFormatFactory</tt> through which <tt>MediaFormat</tt>
@@ -1506,4 +1507,12 @@ private static void setupFMJ()
             }
         }
     }
+    
+    /**
+     * Returns a new <tt>EncodingConfiguration</tt> instance.
+     */
+    public EncodingConfiguration getNewEncodingConfiguration()
+    {
+        return new EncodingConfigurationImpl();
+    }
 }
diff --git a/src/org/jitsi/impl/neomedia/MediaUtils.java b/src/org/jitsi/impl/neomedia/MediaUtils.java
index 94846237..d79ced77 100644
--- a/src/org/jitsi/impl/neomedia/MediaUtils.java
+++ b/src/org/jitsi/impl/neomedia/MediaUtils.java
@@ -148,7 +148,7 @@ public class MediaUtils
             MediaType.AUDIO,
             Constants.G722_RTP,
             8000);
-        if (EncodingConfiguration.G729)
+        if (EncodingConfigurationImpl.G729)
         {
             addMediaFormats(
                 (byte) SdpConstants.G729,
diff --git a/src/org/jitsi/impl/neomedia/codec/EncodingConfigurationImpl.java b/src/org/jitsi/impl/neomedia/codec/EncodingConfigurationImpl.java
new file mode 100644
index 00000000..59035585
--- /dev/null
+++ b/src/org/jitsi/impl/neomedia/codec/EncodingConfigurationImpl.java
@@ -0,0 +1,434 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jitsi.impl.neomedia.codec;
+
+import java.io.*;
+import java.util.*;
+
+import javax.media.*;
+
+import org.jitsi.impl.neomedia.*;
+import org.jitsi.impl.neomedia.format.*;
+import org.jitsi.service.configuration.*;
+import org.jitsi.service.libjitsi.*;
+import org.jitsi.service.neomedia.*;
+import org.jitsi.service.neomedia.codec.*;
+import org.jitsi.service.neomedia.format.*;
+import org.jitsi.util.*;
+
+/**
+ * Simple configuration of encoding priorities.
+ *
+ * @author Damian Minkov
+ * @author Lyubomir Marinov
+ * @author Boris Grozev
+ */
+public class EncodingConfigurationImpl extends EncodingConfiguration
+{
+    /**
+     * The SDP preference property.
+     */
+    private static final String PROP_SDP_PREFERENCE
+        = "net.java.sip.communicator.impl.neomedia.codec.EncodingConfiguration";
+
+    /**
+     * The indicator which determines whether the G.729 codec is enabled.
+     *
+     * WARNING: The use of G.729 may require a license fee and/or royalty fee in
+     * some countries and is licensed by
+     * <a href="http://www.sipro.com">SIPRO Lab Telecom</a>.
+     */
+    public static final boolean G729 = false;
+
+    /**
+     * The additional custom JMF codecs.
+     */
+    private static final String[] CUSTOM_CODECS =
+        {
+            "org.jitsi.impl.neomedia.codec.audio.alaw.DePacketizer",
+            "org.jitsi.impl.neomedia.codec.audio.alaw.JavaEncoder",
+            "org.jitsi.impl.neomedia.codec.audio.alaw.Packetizer",
+            "org.jitsi.impl.neomedia.codec.audio.ulaw.JavaDecoder",
+            "org.jitsi.impl.neomedia.codec.audio.ulaw.JavaEncoder",
+            "org.jitsi.impl.neomedia.codec.audio.ulaw.Packetizer",
+            "org.jitsi.impl.neomedia.codec.audio.speex.JNIDecoder",
+            "org.jitsi.impl.neomedia.codec.audio.speex.JNIEncoder",
+            "org.jitsi.impl.neomedia.codec.audio.speex.SpeexResampler",
+            "org.jitsi.impl.neomedia.codec.audio.speex.JavaDecoder",
+            "org.jitsi.impl.neomedia.codec.audio.speex.JavaEncoder",
+            "org.jitsi.impl.neomedia.codec.audio.mp3.JNIEncoder",
+            "org.jitsi.impl.neomedia.codec.audio.ilbc.JavaDecoder",
+            "org.jitsi.impl.neomedia.codec.audio.ilbc.JavaEncoder",
+            G729
+                ? "org.jitsi.impl.neomedia.codec.audio.g729.JavaDecoder"
+                : null,
+            G729
+                ? "org.jitsi.impl.neomedia.codec.audio.g729.JavaEncoder"
+                : null,
+            "net.java.sip.communicator.impl.neomedia.codec.audio.g722.JNIDecoder",
+            "net.java.sip.communicator.impl.neomedia.codec.audio.g722.JNIEncoder",
+            "org.jitsi.impl.neomedia.codec.audio.gsm.Decoder",
+            "org.jitsi.impl.neomedia.codec.audio.gsm.Encoder",
+            "org.jitsi.impl.neomedia.codec.audio.gsm.DePacketizer",
+            "org.jitsi.impl.neomedia.codec.audio.gsm.Packetizer",
+            "org.jitsi.impl.neomedia.codec.audio.silk.JavaDecoder",
+            "org.jitsi.impl.neomedia.codec.audio.silk.JavaEncoder",
+            "org.jitsi.impl.neomedia.codec.video.h263p.DePacketizer",
+            "org.jitsi.impl.neomedia.codec.video.h263p.JNIDecoder",
+            "org.jitsi.impl.neomedia.codec.video.h263p.JNIEncoder",
+            "org.jitsi.impl.neomedia.codec.video.h263p.Packetizer",
+            "org.jitsi.impl.neomedia.codec.video.h264.DePacketizer",
+            "org.jitsi.impl.neomedia.codec.video.h264.JNIDecoder",
+            "org.jitsi.impl.neomedia.codec.video.h264.JNIEncoder",
+            "org.jitsi.impl.neomedia.codec.video.h264.Packetizer",
+            "org.jitsi.impl.neomedia.codec.video.SwScaler"
+        };
+    
+    /**
+     * Whether custom codecs have been registered with JFM
+     */
+    private static boolean codecsRegistered = false;
+    
+    /**
+     * Whether custom packages have been registered with JFM
+     */
+    private static boolean packagesRegistered = false;
+
+    /**
+     * The package prefixes of the additional JMF <tt>DataSource</tt>s (e.g. low
+     * latency PortAudio and ALSA <tt>CaptureDevice</tt>s).
+     */
+    private static final String[] CUSTOM_PACKAGES
+        = new String[]
+                {
+                    "org.jitsi.impl.neomedia.jmfext",
+                    "net.java.sip.communicator.impl.neomedia.jmfext",
+                    "net.sf.fmj"
+                };
+    
+    /**
+     * Constructor. Loads the hard-coded default preferences and registers
+     * packages and codecs with JMF.
+     */
+    public EncodingConfigurationImpl()
+    {
+        initializeFormatPreferences();
+        
+        registerCustomPackages();
+        registerCustomCodecs();
+    }
+
+    /**
+     * Sets default format preferences.
+     */
+    private void initializeFormatPreferences()
+    {
+        // first init default preferences
+        // video
+        setEncodingPreference(
+            "H264",
+            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
+            1100);
+
+        setEncodingPreference(
+            "H263-1998",
+            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
+            0);
+        /*
+        setEncodingPreference(
+            "H263",
+            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
+            1000);
+        */
+        setEncodingPreference(
+            "JPEG",
+            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
+            950);
+        setEncodingPreference(
+            "H261",
+            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
+            800);
+
+        // audio
+        setEncodingPreference("G722", 8000 /* actually, 16 kHz */, 705);
+        setEncodingPreference("SILK", 24000, 704);
+        setEncodingPreference("SILK", 16000, 703);
+        setEncodingPreference("speex", 32000, 701);
+        setEncodingPreference("speex", 16000, 700);
+        setEncodingPreference("PCMU", 8000, 650);
+        setEncodingPreference("PCMA", 8000, 600);
+        setEncodingPreference("iLBC", 8000, 500);
+        setEncodingPreference("GSM", 8000, 450);
+        setEncodingPreference("speex", 8000, 352);
+        setEncodingPreference("DVI4", 8000, 300);
+        setEncodingPreference("DVI4", 16000, 250);
+        setEncodingPreference("G723", 8000, 150);
+
+        setEncodingPreference("SILK", 12000, 0);
+        setEncodingPreference("SILK", 8000, 0);
+        setEncodingPreference("G729", 8000, 0 /* proprietary */);
+
+        // enables by default telephone event(DTMF rfc4733), with lowest
+        // priority as it is not needed to order it with audio codecs
+        setEncodingPreference(Constants.TELEPHONE_EVENT, 8000, 1);
+        
+    }
+
+    /**
+     * Sets the priority of the given encoding and updates the configuration
+     * via the configuration service.
+     *
+     * @param encoding the <tt>MediaFormat</tt> specifying the encoding to set
+     * the priority of
+     * @param priority a positive <tt>int</tt> indicating the priority of
+     * <tt>encoding</tt> to set
+     * @param updateConfig Whether configuration should be updated.
+     */
+    @Override
+    public void setPriority(MediaFormat encoding, int priority,
+        boolean updateConfig)
+    {
+        super.setPriority(encoding, priority);
+        
+        if(updateConfig)
+        {
+            String encodingEncoding = encoding.getEncoding();
+
+            // save the settings
+            LibJitsi.getConfigurationService().setProperty(
+                    PROP_SDP_PREFERENCE
+                        + "."
+                        + getEncodingPreferenceKey(encoding),
+                    priority);
+        }
+    }
+   
+    /**
+     * Register in JMF the custom codecs we provide
+     */
+    private void registerCustomCodecs()
+    {
+        if(codecsRegistered)
+        {
+            return;
+        }
+        
+        // Register the custom codec which haven't already been registered.
+        @SuppressWarnings("unchecked")
+        Collection<String> registeredPlugins
+            = new HashSet<String>(
+                    PlugInManager.getPlugInList(
+                            null,
+                            null,
+                            PlugInManager.CODEC));
+        boolean commit = false;
+
+        // Remove JavaRGBToYUV.
+        PlugInManager.removePlugIn(
+                "com.sun.media.codec.video.colorspace.JavaRGBToYUV",
+                PlugInManager.CODEC);
+        PlugInManager.removePlugIn(
+                "com.sun.media.codec.video.colorspace.JavaRGBConverter",
+                PlugInManager.CODEC);
+        PlugInManager.removePlugIn(
+                "com.sun.media.codec.video.colorspace.RGBScaler",
+                PlugInManager.CODEC);
+
+        // Remove JMF's H263 codec.
+        PlugInManager.removePlugIn(
+                "com.sun.media.codec.video.vh263.NativeDecoder",
+                PlugInManager.CODEC);
+        PlugInManager.removePlugIn(
+                "com.ibm.media.codec.video.h263.NativeEncoder",
+                PlugInManager.CODEC);
+
+        // Remove JMF's GSM codec. As working only on some OS.
+        String gsmCodecPackage = "com.ibm.media.codec.audio.gsm.";
+        String[] gsmCodecClasses
+            = new String[]
+                    {
+                        "JavaDecoder",
+                        "JavaDecoder_ms",
+                        "JavaEncoder",
+                        "JavaEncoder_ms",
+                        "NativeDecoder",
+                        "NativeDecoder_ms",
+                        "NativeEncoder",
+                        "NativeEncoder_ms",
+                        "Packetizer"
+                    };
+        for(String gsmCodecClass : gsmCodecClasses)
+        {
+            PlugInManager.removePlugIn(
+                gsmCodecPackage + gsmCodecClass,
+                PlugInManager.CODEC);
+        }
+
+        /*
+         * Remove FMJ's JavaSoundCodec because it seems to slow down the
+         * building of the filter graph and we do not currently seem to need it.
+         */
+        PlugInManager.removePlugIn(
+                "net.sf.fmj.media.codec.JavaSoundCodec",
+                PlugInManager.CODEC);
+
+        for (String className : CUSTOM_CODECS)
+        {
+
+            /*
+             * A codec with a className of null is configured at compile time to
+             * not be registered.
+             */
+            if (className == null)
+                continue;
+
+            if (registeredPlugins.contains(className))
+            {
+                if (logger.isDebugEnabled())
+                    logger.debug(
+                        "Codec " + className + " is already registered");
+            }
+            else
+            {
+                commit = true;
+
+                boolean registered;
+                Throwable exception = null;
+
+                try
+                {
+                    Codec codec = (Codec)
+                        Class.forName(className).newInstance();
+
+                    registered =
+                        PlugInManager.addPlugIn(
+                            className,
+                            codec.getSupportedInputFormats(),
+                            codec.getSupportedOutputFormats(null),
+                            PlugInManager.CODEC);
+                }
+                catch (Throwable ex)
+                {
+                    registered = false;
+                    exception = ex;
+                }
+                if (registered)
+                {
+                    if (logger.isDebugEnabled())
+                        logger.debug(
+                            "Codec "
+                                + className
+                                + " is successfully registered");
+                }
+                else
+                {
+                    if (logger.isDebugEnabled())
+                        logger.debug(
+                            "Codec "
+                                + className
+                                + " is NOT succsefully registered", exception);
+                }
+            }
+        }
+
+        /*
+         * If Jitsi provides a codec which is also provided by FMJ and/or JMF,
+         * use Jitsi's version.
+         */
+        @SuppressWarnings("unchecked")
+        Vector<String> codecs
+            = PlugInManager.getPlugInList(null, null, PlugInManager.CODEC);
+
+        if (codecs != null)
+        {
+            boolean setPlugInList = false;
+
+            for (int i = CUSTOM_CODECS.length - 1; i >= 0; i--)
+            {
+                String className = CUSTOM_CODECS[i];
+
+                if (className != null)
+                {
+                    int classNameIndex = codecs.indexOf(className);
+
+                    if (classNameIndex != -1)
+                    {
+                        codecs.remove(classNameIndex);
+                        codecs.add(0, className);
+                        setPlugInList = true;
+                    }
+                }
+            }
+
+            if (setPlugInList)
+                PlugInManager.setPlugInList(codecs, PlugInManager.CODEC);
+        }
+
+        if (commit && !MediaServiceImpl.isJmfRegistryDisableLoad())
+        {
+            try
+            {
+                PlugInManager.commit();
+            }
+            catch (IOException ex)
+            {
+                logger.error("Cannot commit to PlugInManager", ex);
+            }
+        }
+        
+        codecsRegistered = true;
+    }
+
+    /**
+     * Register in JMF the custom packages we provide
+     */
+    private void registerCustomPackages()
+    {
+        if(packagesRegistered)
+        {
+            return;
+        }
+        
+        @SuppressWarnings("unchecked")
+        Vector<String> packages = PackageManager.getProtocolPrefixList();
+        boolean loggerIsDebugEnabled = logger.isDebugEnabled();
+
+        for (String customPackage : CUSTOM_PACKAGES)
+        {
+            /*
+             * Linear search in a loop but it doesn't have to scale since the
+             * list is always short.
+             */
+            if (!packages.contains(customPackage))
+            {
+                packages.add(customPackage);
+                if (loggerIsDebugEnabled)
+                    if (logger.isDebugEnabled())
+                        logger.debug("Adding package  : " + customPackage);
+            }
+        }
+
+        PackageManager.setProtocolPrefixList(packages);
+        PackageManager.commitProtocolPrefixList();
+        if (loggerIsDebugEnabled)
+        {
+            if (logger.isDebugEnabled())
+                logger.debug(
+                    "Registering new protocol prefix list: " + packages);
+        }
+        
+        packagesRegistered = true;
+    }
+    
+    /**
+     * Loads the "global" preferences.
+     */
+    public void loadConfig()
+    {
+        loadFormatPreferencesFromConfig(PROP_SDP_PREFERENCE);
+    }
+}
diff --git a/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java b/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java
index 7ce90c42..95a55fc2 100644
--- a/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java
+++ b/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java
@@ -19,6 +19,7 @@
 import org.jitsi.impl.neomedia.conference.*;
 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.event.*;
 import org.jitsi.service.neomedia.format.*;
@@ -443,6 +444,27 @@ public List<MediaFormat> getSupportedFormats(
     {
         return device.getSupportedFormats();
     }
+    
+    /**
+     * Gets the list of <tt>MediaFormat</tt>s supported by this
+     * <tt>MediaDevice</tt> and enabled in <tt>encodingConfiguration</tt>.
+     *
+     * @param sendPreset not used
+     * @param receivePreset not used
+     * @param encodingConfiguration the <tt>EncodingConfiguration</tt> instance
+     * to use
+     * @return the list of <tt>MediaFormat</tt>s supported by this
+     * <tt>MediaDevice</tt> and enabled in <tt>encodingConfiguration</tt>.
+     * @see MediaDevice#getSupportedFormats(QualityPreset, QualityPreset,
+     * EncodingConfiguration)
+     */
+    public List<MediaFormat> getSupportedFormats(
+            QualityPreset sendPreset,
+            QualityPreset receivePreset,
+            EncodingConfiguration encodingConfiguration)
+    {
+        return device.getSupportedFormats(encodingConfiguration);
+    }
 
     /**
      * Gets the actual <tt>MediaDevice</tt> which this <tt>MediaDevice</tt> is
diff --git a/src/org/jitsi/impl/neomedia/device/MediaDeviceImpl.java b/src/org/jitsi/impl/neomedia/device/MediaDeviceImpl.java
index cb79046f..b5a24b4b 100644
--- a/src/org/jitsi/impl/neomedia/device/MediaDeviceImpl.java
+++ b/src/org/jitsi/impl/neomedia/device/MediaDeviceImpl.java
@@ -21,6 +21,7 @@
 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.util.*;
@@ -331,7 +332,8 @@ public MediaType getMediaType()
 
     /**
      * Gets the list of <tt>MediaFormat</tt>s supported by this
-     * <tt>MediaDevice</tt>.
+     * <tt>MediaDevice</tt>. Uses the <tt>EncodingConfiguration</tt> from the
+     * media service, which contains all known encodings.
      *
      * @param sendPreset the preset used to set some of the format parameters,
      * used for video and settings.
@@ -343,11 +345,49 @@ public MediaType getMediaType()
     public List<MediaFormat> getSupportedFormats(
             QualityPreset sendPreset,
             QualityPreset receivePreset)
+    {
+        return getSupportedFormats(sendPreset, receivePreset,
+                NeomediaServiceUtils.getMediaServiceImpl()
+                    .getEncodingConfiguration());
+    }
+    
+    /**
+     * Gets the list of <tt>MediaFormat</tt>s supported by this
+     * <tt>MediaDevice</tt> and enabled in <tt>encodingConfiguration</tt>.
+     *
+     * @param encodingConfiguration the <tt>EncodingConfiguration</tt> instance
+     * to use
+     * @return the list of <tt>MediaFormat</tt>s supported by this device
+     * and enabled in <tt>encodingConfiguration</tt>.
+     * @see MediaDevice#getSupportedFormats()
+     */
+    public List<MediaFormat> getSupportedFormats(
+            EncodingConfiguration encodingConfiguration)
+    {
+            return getSupportedFormats(null, null, encodingConfiguration);
+    }
+    
+    /**
+     * Gets the list of <tt>MediaFormat</tt>s supported by this
+     * <tt>MediaDevice</tt> and enabled in <tt>encodingConfiguration</tt>.
+     *
+     * @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 <tt>EncodingConfiguration</tt> instance
+     * to use
+     * @return the list of <tt>MediaFormat</tt>s supported by this device
+     * and enabled in <tt>encodingConfiguration</tt>.
+     * @see MediaDevice#getSupportedFormats()
+     */
+    public List<MediaFormat> getSupportedFormats(
+            QualityPreset sendPreset,
+            QualityPreset receivePreset,
+            EncodingConfiguration encodingConfiguration)
     {
         MediaServiceImpl mediaServiceImpl
             = NeomediaServiceUtils.getMediaServiceImpl();
-        EncodingConfiguration encodingConfiguration
-            = mediaServiceImpl.getEncodingConfiguration();
         MediaFormat[] supportedEncodings
             = encodingConfiguration.getSupportedEncodings(getMediaType());
         List<MediaFormat> supportedFormats = new ArrayList<MediaFormat>();
diff --git a/src/org/jitsi/impl/neomedia/device/VideoTranslatorMediaDevice.java b/src/org/jitsi/impl/neomedia/device/VideoTranslatorMediaDevice.java
index 9757fec4..32816bc7 100644
--- a/src/org/jitsi/impl/neomedia/device/VideoTranslatorMediaDevice.java
+++ b/src/org/jitsi/impl/neomedia/device/VideoTranslatorMediaDevice.java
@@ -13,6 +13,7 @@
 
 import org.jitsi.impl.neomedia.format.*;
 import org.jitsi.service.neomedia.*;
+import org.jitsi.service.neomedia.codec.*;
 import org.jitsi.service.neomedia.device.*;
 import org.jitsi.service.neomedia.format.*;
 
@@ -211,6 +212,32 @@ public List<MediaFormat> getSupportedFormats(
         return device.getSupportedFormats(localPreset, remotePreset);
     }
 
+    /**
+     * Returns a list of <tt>MediaFormat</tt> instances representing the media
+     * formats supported by this <tt>MediaDevice</tt> and enabled in
+     * <tt>encodingConfiguration</tt>..
+     *
+     * @param localPreset the preset used to set the send format parameters,
+     * used for video and settings
+     * @param remotePreset the preset used to set the receive format parameters,
+     * used for video and settings
+     * @param encodingConfiguration the <tt>EncodingConfiguration</tt> instance
+     * to use
+     * @return the list of <tt>MediaFormat</tt>s supported by this device
+     * and enabled in <tt>encodingConfiguration</tt>.
+     * @see MediaDevice#getSupportedFormats(QualityPreset, QualityPreset,
+     * EncodingConfiguration)
+     */
+    public List<MediaFormat> getSupportedFormats(
+            QualityPreset localPreset,
+            QualityPreset remotePreset,
+            EncodingConfiguration encodingConfiguration)
+    {
+        return device.getSupportedFormats(localPreset,
+                remotePreset,
+                encodingConfiguration);
+    }
+    
     /**
      * Gets the actual <tt>MediaDevice</tt> which this <tt>MediaDevice</tt> is
      * effectively built on top of and forwarding to.
diff --git a/src/org/jitsi/impl/neomedia/format/MediaFormatFactoryImpl.java b/src/org/jitsi/impl/neomedia/format/MediaFormatFactoryImpl.java
index b2f9f82f..80562319 100644
--- a/src/org/jitsi/impl/neomedia/format/MediaFormatFactoryImpl.java
+++ b/src/org/jitsi/impl/neomedia/format/MediaFormatFactoryImpl.java
@@ -14,6 +14,7 @@
 import org.jitsi.impl.neomedia.*;
 import org.jitsi.impl.neomedia.codec.*;
 import org.jitsi.service.neomedia.*;
+import org.jitsi.service.neomedia.codec.*;
 import org.jitsi.service.neomedia.format.*;
 import org.jitsi.util.*;
 
diff --git a/src/org/jitsi/service/neomedia/MediaConfigurationService.java b/src/org/jitsi/service/neomedia/MediaConfigurationService.java
new file mode 100644
index 00000000..ba6dfc56
--- /dev/null
+++ b/src/org/jitsi/service/neomedia/MediaConfigurationService.java
@@ -0,0 +1,55 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package org.jitsi.service.neomedia;
+
+import java.awt.*;
+import org.jitsi.service.neomedia.codec.*;
+
+/**
+ * An interface that exposes the <tt>Component</tt>s used in media
+ * configuration user interfaces.
+ * 
+ * @author Boris Grozev
+ */
+public interface MediaConfigurationService
+{
+    /**
+     * Returns a <tt>Component</tt> for audio configuration
+     * 
+     * @return A <tt>Component</tt> for audio configuration
+     */
+    public Component createAudioConfigPanel();
+    
+    /**
+     * Returns a <tt>Component</tt> for video configuration
+     * 
+     * @return A <tt>Component</tt> for video configuration
+     */
+    public Component createVideoConfigPanel();
+    
+    /**
+     * Returns a <tt>Component</tt> for encodings configuration (either audio or video)
+     * @param mediaType The type of media -- either MediaType.AUDIO or
+     * MediaType.VIDEO
+     * @param encodingConfiguration The <tt>EncodingConfiguration</tt> instance
+     * to use. If null, creates one on it's own.
+     * @param autoUpdateConfig Whether we should update the configuration after
+     * every change. Useful, because in the main audio/video encoding 
+     * configuration we want the changes to apply instantaneously, while in the
+     * account creation wizards we want to delay the update until the form is
+     * committed.
+     * @return The <tt>Component</tt> for encodings configuration
+     */
+    public Component createEncodingControls(MediaType mediaType,
+            EncodingConfiguration encodingConfiguration,
+            boolean autoUpdateConfig);
+    
+    /**
+     * Returns a new <tt>EncodingConfiguration</tt> instance
+     * @return a new <tt>EncodingConfiguration</tt> instance
+     */
+    public EncodingConfiguration getNewEncodingConfiguration();
+}
diff --git a/src/org/jitsi/service/neomedia/MediaService.java b/src/org/jitsi/service/neomedia/MediaService.java
index 50b37f5b..72aa01e8 100644
--- a/src/org/jitsi/service/neomedia/MediaService.java
+++ b/src/org/jitsi/service/neomedia/MediaService.java
@@ -9,6 +9,7 @@
 import java.beans.*;
 import java.util.*;
 
+import org.jitsi.service.neomedia.codec.*;
 import org.jitsi.service.neomedia.device.*;
 import org.jitsi.service.neomedia.format.*;
 
@@ -317,4 +318,9 @@ public java.awt.Point getOriginForDesktopStreamingDevice(
      * notified about changes in the values of the properties of this instance
      */
     public void removePropertyChangeListener(PropertyChangeListener listener);
+    
+    /**
+     * Returns a new <tt>EncodingConfiguration</tt> instance.
+     */
+    public EncodingConfiguration getNewEncodingConfiguration();
 }
diff --git a/src/org/jitsi/impl/neomedia/codec/EncodingConfiguration.java b/src/org/jitsi/service/neomedia/codec/EncodingConfiguration.java
similarity index 50%
rename from src/org/jitsi/impl/neomedia/codec/EncodingConfiguration.java
rename to src/org/jitsi/service/neomedia/codec/EncodingConfiguration.java
index 51413b51..bf8fa705 100644
--- a/src/org/jitsi/impl/neomedia/codec/EncodingConfiguration.java
+++ b/src/org/jitsi/service/neomedia/codec/EncodingConfiguration.java
@@ -4,15 +4,11 @@
  * Distributable under LGPL license.
  * See terms of license at gnu.org.
  */
-package org.jitsi.impl.neomedia.codec;
+package org.jitsi.service.neomedia.codec;
 
-import java.io.*;
 import java.util.*;
 
-import javax.media.*;
-
 import org.jitsi.impl.neomedia.*;
-import org.jitsi.impl.neomedia.format.*;
 import org.jitsi.service.configuration.*;
 import org.jitsi.service.libjitsi.*;
 import org.jitsi.service.neomedia.*;
@@ -20,90 +16,20 @@
 import org.jitsi.util.*;
 
 /**
- * Simple configuration of encoding priorities.
- *
+ * Abstract class that manages encoding configurations. It holds information
+ * about supported formats.
+ * 
  * @author Damian Minkov
  * @author Lyubomir Marinov
+ * @author Boris Grozev
  */
-public class EncodingConfiguration
+public abstract class EncodingConfiguration
 {
-
     /**
      * The <tt>Logger</tt> used by this <tt>EncodingConfiguration</tt> instance
      * for logging output.
      */
-    private final Logger logger = Logger.getLogger(EncodingConfiguration.class);
-
-    /**
-     * The SDP preference property.
-     */
-    private static final String PROP_SDP_PREFERENCE
-        = "net.java.sip.communicator.impl.neomedia.codec.EncodingConfiguration";
-
-    /**
-     * The indicator which determines whether the G.729 codec is enabled.
-     *
-     * WARNING: The use of G.729 may require a license fee and/or royalty fee in
-     * some countries and is licensed by
-     * <a href="http://www.sipro.com">SIPRO Lab Telecom</a>.
-     */
-    public static final boolean G729 = false;
-
-    /**
-     * The additional custom JMF codecs.
-     */
-    private static final String[] CUSTOM_CODECS =
-        {
-            "org.jitsi.impl.neomedia.codec.audio.alaw.DePacketizer",
-            "org.jitsi.impl.neomedia.codec.audio.alaw.JavaEncoder",
-            "org.jitsi.impl.neomedia.codec.audio.alaw.Packetizer",
-            "org.jitsi.impl.neomedia.codec.audio.ulaw.JavaDecoder",
-            "org.jitsi.impl.neomedia.codec.audio.ulaw.JavaEncoder",
-            "org.jitsi.impl.neomedia.codec.audio.ulaw.Packetizer",
-            "org.jitsi.impl.neomedia.codec.audio.speex.JNIDecoder",
-            "org.jitsi.impl.neomedia.codec.audio.speex.JNIEncoder",
-            "org.jitsi.impl.neomedia.codec.audio.speex.SpeexResampler",
-            "org.jitsi.impl.neomedia.codec.audio.speex.JavaDecoder",
-            "org.jitsi.impl.neomedia.codec.audio.speex.JavaEncoder",
-            "org.jitsi.impl.neomedia.codec.audio.mp3.JNIEncoder",
-            "org.jitsi.impl.neomedia.codec.audio.ilbc.JavaDecoder",
-            "org.jitsi.impl.neomedia.codec.audio.ilbc.JavaEncoder",
-            G729
-                ? "org.jitsi.impl.neomedia.codec.audio.g729.JavaDecoder"
-                : null,
-            G729
-                ? "org.jitsi.impl.neomedia.codec.audio.g729.JavaEncoder"
-                : null,
-            "net.java.sip.communicator.impl.neomedia.codec.audio.g722.JNIDecoder",
-            "net.java.sip.communicator.impl.neomedia.codec.audio.g722.JNIEncoder",
-            "org.jitsi.impl.neomedia.codec.audio.gsm.Decoder",
-            "org.jitsi.impl.neomedia.codec.audio.gsm.Encoder",
-            "org.jitsi.impl.neomedia.codec.audio.gsm.DePacketizer",
-            "org.jitsi.impl.neomedia.codec.audio.gsm.Packetizer",
-            "org.jitsi.impl.neomedia.codec.audio.silk.JavaDecoder",
-            "org.jitsi.impl.neomedia.codec.audio.silk.JavaEncoder",
-            "org.jitsi.impl.neomedia.codec.video.h263p.DePacketizer",
-            "org.jitsi.impl.neomedia.codec.video.h263p.JNIDecoder",
-            "org.jitsi.impl.neomedia.codec.video.h263p.JNIEncoder",
-            "org.jitsi.impl.neomedia.codec.video.h263p.Packetizer",
-            "org.jitsi.impl.neomedia.codec.video.h264.DePacketizer",
-            "org.jitsi.impl.neomedia.codec.video.h264.JNIDecoder",
-            "org.jitsi.impl.neomedia.codec.video.h264.JNIEncoder",
-            "org.jitsi.impl.neomedia.codec.video.h264.Packetizer",
-            "org.jitsi.impl.neomedia.codec.video.SwScaler"
-        };
-
-    /**
-     * The package prefixes of the additional JMF <tt>DataSource</tt>s (e.g. low
-     * latency PortAudio and ALSA <tt>CaptureDevice</tt>s).
-     */
-    private static final String[] CUSTOM_PACKAGES
-        = new String[]
-                {
-                    "org.jitsi.impl.neomedia.jmfext",
-                    "net.java.sip.communicator.impl.neomedia.jmfext",
-                    "net.sf.fmj"
-                };
+    protected final Logger logger = Logger.getLogger(EncodingConfiguration.class);
 
     /**
      * The <tt>Comparator</tt> which sorts the sets according to the settings in
@@ -112,6 +38,7 @@ public class EncodingConfiguration
     private final Comparator<MediaFormat> encodingComparator
         = new Comparator<MediaFormat>()
                 {
+                    @Override
                     public int compare(MediaFormat s1, MediaFormat s2)
                     {
                         return compareEncodingPreferences(s1, s2);
@@ -125,7 +52,7 @@ public int compare(MediaFormat s1, MediaFormat s2)
      * would be decorelated and other components (such as the UI) should present
      * them separately.
      */
-    private final Map<String, Integer> encodingPreferences
+    protected final Map<String, Integer> encodingPreferences
         = new HashMap<String, Integer>();
 
     /**
@@ -140,143 +67,6 @@ public int compare(MediaFormat s1, MediaFormat s2)
      */
     private Set<MediaFormat> supportedVideoEncodings;
 
-    /**
-     * Default constructor.
-     */
-    public EncodingConfiguration()
-    {
-        initializeFormatPreferences();
-        registerCustomPackages();
-        registerCustomCodecs();
-    }
-
-    /**
-     * Retrieves (from the configuration service) preferences specified for
-     * various formats and assigns default ones to those that haven't been
-     * mentioned.
-     */
-    private void initializeFormatPreferences()
-    {
-        // first init default preferences
-        // video
-        setEncodingPreference(
-            "H264",
-            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
-            1100);
-
-        setEncodingPreference(
-            "H263-1998",
-            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
-            0);
-        /*
-        setEncodingPreference(
-            "H263",
-            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
-            1000);
-        */
-        setEncodingPreference(
-            "JPEG",
-            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
-            950);
-        setEncodingPreference(
-            "H261",
-            VideoMediaFormatImpl.DEFAULT_CLOCK_RATE,
-            800);
-
-        // audio
-        setEncodingPreference("G722", 8000 /* actually, 16 kHz */, 705);
-        setEncodingPreference("SILK", 24000, 704);
-        setEncodingPreference("SILK", 16000, 703);
-        setEncodingPreference("speex", 32000, 701);
-        setEncodingPreference("speex", 16000, 700);
-        setEncodingPreference("PCMU", 8000, 650);
-        setEncodingPreference("PCMA", 8000, 600);
-        setEncodingPreference("iLBC", 8000, 500);
-        setEncodingPreference("GSM", 8000, 450);
-        setEncodingPreference("speex", 8000, 352);
-        setEncodingPreference("DVI4", 8000, 300);
-        setEncodingPreference("DVI4", 16000, 250);
-        setEncodingPreference("G723", 8000, 150);
-
-        setEncodingPreference("SILK", 12000, 0);
-        setEncodingPreference("SILK", 8000, 0);
-        setEncodingPreference("G729", 8000, 0 /* proprietary */);
-
-        // enables by default telephone event(DTMF rfc4733), with lowest
-        // priority as it is not needed to order it with audio codecs
-        setEncodingPreference(Constants.TELEPHONE_EVENT, 8000, 1);
-
-        // now override with those that are specified by the user.
-        ConfigurationService cfg = LibJitsi.getConfigurationService();
-
-        if (cfg != null)
-        {
-            for (String pName
-                    : cfg.getPropertyNamesByPrefix(PROP_SDP_PREFERENCE, false))
-            {
-                String prefStr = cfg.getString(pName);
-                String fmtName = pName.substring(pName.lastIndexOf('.') + 1);
-
-                // 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 (cfg.getString(PROP_SDP_PREFERENCE + "." + fmtName)
-                            != null)
-                        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();
-    }
-
     /**
      * Updates the codecs in the supported sets according to the preferences in
      * encodingPreferences. If the preference value is <tt>0</tt>, the codec is
@@ -302,13 +92,17 @@ private void updateSupportedEncodings()
      */
     private Set<MediaFormat> updateSupportedEncodings(MediaType type)
     {
-        Set<MediaFormat> supported
+        Set<MediaFormat> enabled
             = new TreeSet<MediaFormat>(encodingComparator);
 
         for (MediaFormat format : getAvailableEncodings(type))
+        {
             if (getPriority(format) > 0)
-                supported.add(format);
-        return supported;
+            {
+                enabled.add(format);
+            }
+        }
+        return enabled;
     }
 
     /**
@@ -321,7 +115,7 @@ private Set<MediaFormat> updateSupportedEncodings(MediaType type)
      * @param clockRate clock rate
      * @param pref a positive int indicating the preference for that encoding.
      */
-    private void setEncodingPreference(
+    protected void setEncodingPreference(
             String encoding, double clockRate,
             int pref)
     {
@@ -374,37 +168,29 @@ public void setPriority(MediaFormat encoding, int priority)
 
         updateSupportedEncodings();
     }
-
+    
     /**
-     * Sets the priority of the given encoding in the configuration service.
-     *
+     * Sets <tt>priority</tt> as the preference associated with
+     * <tt>encoding</tt> (with a call to <tt>setPriority(MediaFormat, int)</tt>
+     * for example), and also, if <tt>updateConfig</tt> is <tt>true</tt>,
+     * updates configuration. 
      * @param encoding the <tt>MediaFormat</tt> specifying the encoding to set
      * the priority of
      * @param priority a positive <tt>int</tt> indicating the priority of
      * <tt>encoding</tt> to set
+     * @param updateConfig Whether to update configuration or not.
      */
-    public void setPriorityConfig(MediaFormat encoding, int priority)
-    {
-        String encodingEncoding = encoding.getEncoding();
+    public abstract void setPriority(MediaFormat encoding, int priority,
+            boolean updateConfig);
 
-        // save the settings
-        LibJitsi.getConfigurationService().setProperty(
-                PROP_SDP_PREFERENCE
-                    + "."
-                    + encodingEncoding
-                    + "/"
-                    + encoding.getClockRateString(),
-                priority);
-    }
 
     /**
-     * Set the priority for a <tt>MediaFormat</tt>.
+     * Get the priority for a <tt>MediaFormat</tt>.
      * @param encoding the <tt>MediaFormat</tt>
      * @return the priority
      */
     public int getPriority(MediaFormat encoding)
     {
-
         /*
          * Directly returning encodingPreference.get(encoding) will throw a
          * NullPointerException if encodingPreferences does not contain a
@@ -416,209 +202,7 @@ public int getPriority(MediaFormat encoding)
         return (priority == null) ? 0 : priority;
     }
 
-    /**
-     * Register in JMF the custom codecs we provide
-     */
-    private void registerCustomCodecs()
-    {
-        // Register the custom codec which haven't already been registered.
-        @SuppressWarnings("unchecked")
-        Collection<String> registeredPlugins
-            = new HashSet<String>(
-                    PlugInManager.getPlugInList(
-                            null,
-                            null,
-                            PlugInManager.CODEC));
-        boolean commit = false;
-
-        // Remove JavaRGBToYUV.
-        PlugInManager.removePlugIn(
-                "com.sun.media.codec.video.colorspace.JavaRGBToYUV",
-                PlugInManager.CODEC);
-        PlugInManager.removePlugIn(
-                "com.sun.media.codec.video.colorspace.JavaRGBConverter",
-                PlugInManager.CODEC);
-        PlugInManager.removePlugIn(
-                "com.sun.media.codec.video.colorspace.RGBScaler",
-                PlugInManager.CODEC);
-
-        // Remove JMF's H263 codec.
-        PlugInManager.removePlugIn(
-                "com.sun.media.codec.video.vh263.NativeDecoder",
-                PlugInManager.CODEC);
-        PlugInManager.removePlugIn(
-                "com.ibm.media.codec.video.h263.NativeEncoder",
-                PlugInManager.CODEC);
-
-        // Remove JMF's GSM codec. As working only on some OS.
-        String gsmCodecPackage = "com.ibm.media.codec.audio.gsm.";
-        String[] gsmCodecClasses
-            = new String[]
-                    {
-                        "JavaDecoder",
-                        "JavaDecoder_ms",
-                        "JavaEncoder",
-                        "JavaEncoder_ms",
-                        "NativeDecoder",
-                        "NativeDecoder_ms",
-                        "NativeEncoder",
-                        "NativeEncoder_ms",
-                        "Packetizer"
-                    };
-        for(String gsmCodecClass : gsmCodecClasses)
-        {
-            PlugInManager.removePlugIn(
-                gsmCodecPackage + gsmCodecClass,
-                PlugInManager.CODEC);
-        }
-
-        /*
-         * Remove FMJ's JavaSoundCodec because it seems to slow down the
-         * building of the filter graph and we do not currently seem to need it.
-         */
-        PlugInManager.removePlugIn(
-                "net.sf.fmj.media.codec.JavaSoundCodec",
-                PlugInManager.CODEC);
-
-        for (String className : CUSTOM_CODECS)
-        {
-
-            /*
-             * A codec with a className of null is configured at compile time to
-             * not be registered.
-             */
-            if (className == null)
-                continue;
-
-            if (registeredPlugins.contains(className))
-            {
-                if (logger.isDebugEnabled())
-                    logger.debug(
-                        "Codec " + className + " is already registered");
-            }
-            else
-            {
-                commit = true;
-
-                boolean registered;
-                Throwable exception = null;
-
-                try
-                {
-                    Codec codec = (Codec)
-                        Class.forName(className).newInstance();
-
-                    registered =
-                        PlugInManager.addPlugIn(
-                            className,
-                            codec.getSupportedInputFormats(),
-                            codec.getSupportedOutputFormats(null),
-                            PlugInManager.CODEC);
-                }
-                catch (Throwable ex)
-                {
-                    registered = false;
-                    exception = ex;
-                }
-                if (registered)
-                {
-                    if (logger.isDebugEnabled())
-                        logger.debug(
-                            "Codec "
-                                + className
-                                + " is successfully registered");
-                }
-                else
-                {
-                    if (logger.isDebugEnabled())
-                        logger.debug(
-                            "Codec "
-                                + className
-                                + " is NOT succsefully registered", exception);
-                }
-            }
-        }
-
-        /*
-         * If Jitsi provides a codec which is also provided by FMJ and/or JMF,
-         * use Jitsi's version.
-         */
-        @SuppressWarnings("unchecked")
-        Vector<String> codecs
-            = PlugInManager.getPlugInList(null, null, PlugInManager.CODEC);
-
-        if (codecs != null)
-        {
-            boolean setPlugInList = false;
-
-            for (int i = CUSTOM_CODECS.length - 1; i >= 0; i--)
-            {
-                String className = CUSTOM_CODECS[i];
-
-                if (className != null)
-                {
-                    int classNameIndex = codecs.indexOf(className);
-
-                    if (classNameIndex != -1)
-                    {
-                        codecs.remove(classNameIndex);
-                        codecs.add(0, className);
-                        setPlugInList = true;
-                    }
-                }
-            }
-
-            if (setPlugInList)
-                PlugInManager.setPlugInList(codecs, PlugInManager.CODEC);
-        }
-
-        if (commit && !MediaServiceImpl.isJmfRegistryDisableLoad())
-        {
-            try
-            {
-                PlugInManager.commit();
-            }
-            catch (IOException ex)
-            {
-                logger.error("Cannot commit to PlugInManager", ex);
-            }
-        }
-    }
-
-    /**
-     * Register in JMF the custom packages we provide
-     */
-    private void registerCustomPackages()
-    {
-        @SuppressWarnings("unchecked")
-        Vector<String> packages = PackageManager.getProtocolPrefixList();
-        boolean loggerIsDebugEnabled = logger.isDebugEnabled();
-
-        for (String customPackage : CUSTOM_PACKAGES)
-        {
-            /*
-             * Linear search in a loop but it doesn't have to scale since the
-             * list is always short.
-             */
-            if (!packages.contains(customPackage))
-            {
-                packages.add(customPackage);
-                if (loggerIsDebugEnabled)
-                    if (logger.isDebugEnabled())
-                        logger.debug("Adding package  : " + customPackage);
-            }
-        }
-
-        PackageManager.setProtocolPrefixList(packages);
-        PackageManager.commitProtocolPrefixList();
-        if (loggerIsDebugEnabled)
-        {
-            if (logger.isDebugEnabled())
-                logger.debug(
-                    "Registering new protocol prefix list: " + packages);
-        }
-    }
-
+    
     /**
      * Get the available encodings for a specific <tt>MediaType</tt>.
      *
@@ -660,6 +244,7 @@ public MediaFormat[] getSupportedEncodings(MediaType type)
         default:
             return MediaUtils.EMPTY_MEDIA_FORMATS;
         }
+
         return
             supportedEncodings.toArray(
                     new MediaFormat[supportedEncodings.size()]);
@@ -746,8 +331,142 @@ private int compareEncodingPreferences(MediaFormat enc1, MediaFormat enc2)
      * @return the key in {@link #encodingPreferences} which is associated with
      * the priority of the specified <tt>encoding</tt>
      */
-    private String getEncodingPreferenceKey(MediaFormat encoding)
+    protected String getEncodingPreferenceKey(MediaFormat encoding)
     {
         return encoding.getEncoding() + "/" + encoding.getClockRateString();
     }
+    
+    /**
+     * Loads configuration.
+     */
+    public abstract void loadConfig();
+    
+    /**
+     * Parses the properties under <tt>prefix</tt> and loads them.
+     * 
+     * @param prefix The prefix to search the configuration under
+     */
+    public void loadFormatPreferencesFromConfig(String prefix)
+    {
+        ConfigurationService cfg = LibJitsi.getConfigurationService();
+        
+        Map<String, String> properties = new HashMap<String, String>();
+        
+        if (cfg != null)
+        {
+            for (String pName : cfg.getPropertyNamesByPrefix(prefix, false))
+            {
+                properties.put(pName,
+                        cfg.getString(pName));
+            }
+            loadProperties(properties);
+        }
+    }
+        
+    
+   /**
+    * Parses a <tt>Map<String, String></tt> and updates the format preferences
+    * according to it.
+    * The map is expected to have entries in the form of
+    * (formatString, preference).
+    * @param properties The <tt>Map</tt> to parse.
+    */
+    public void loadProperties(Map<String, String> properties)
+    {
+
+            for (String pName
+                    : properties.keySet())
+            {
+                String prefStr = properties.get(pName);
+                String fmtName;
+                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();
+    }
+    
+    
+    /**
+     * Returns a <tt>Map<String, String></tt> that holds the properties
+     * corresponding to the current format preferences
+     * @return A <tt>Map<String, String></tt> that holds the properties
+     * corresponding to the current format preferences.
+     */
+    public Map<String, String> getEncodingProperties()
+    {
+        Map<String, String> encodingProperties = new HashMap<String, String>();
+        for(MediaFormat mf : getAvailableEncodings(MediaType.AUDIO))
+        {
+            encodingProperties.put(getEncodingPreferenceKey(mf),
+                                   "" + getPriority(mf));
+        }
+        for(MediaFormat mf : getAvailableEncodings(MediaType.VIDEO))
+        {
+            encodingProperties.put(getEncodingPreferenceKey(mf),
+                                   "" + getPriority(mf));
+        }
+        return encodingProperties;
+    }
+    
 }
diff --git a/src/org/jitsi/service/neomedia/device/MediaDevice.java b/src/org/jitsi/service/neomedia/device/MediaDevice.java
index 3d732319..d3efe4e1 100644
--- a/src/org/jitsi/service/neomedia/device/MediaDevice.java
+++ b/src/org/jitsi/service/neomedia/device/MediaDevice.java
@@ -9,6 +9,7 @@
 import java.util.*;
 
 import org.jitsi.service.neomedia.*;
+import org.jitsi.service.neomedia.codec.*;
 import org.jitsi.service.neomedia.format.*;
 
 /**
@@ -80,4 +81,24 @@ public interface MediaDevice
     public List<MediaFormat> getSupportedFormats(
             QualityPreset localPreset,
             QualityPreset remotePreset);
+   
+     /**
+     * Returns a list of <tt>MediaFormat</tt> instances representing the media
+     * formats supported by this <tt>MediaDevice</tt> and enabled in
+     * <tt>encodingConfiguration</tt>.
+     *
+     * @param localPreset the preset used to set the send format parameters,
+     * used for video and settings.
+     * @param remotePreset the preset used to set the receive format parameters,
+     * used for video and settings.
+     * @param encodingConfiguration the <tt>EncodingConfiguration<tt> instance
+     * to use.
+     *
+     * @return the list of <tt>MediaFormat</tt>s supported by this device.
+     */
+    public List<MediaFormat> getSupportedFormats(
+            QualityPreset localPreset,
+            QualityPreset remotePreset,
+            EncodingConfiguration encodingConfiguration);
+   
 }
-- 
GitLab