diff --git a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java
index 40d1a50beea325be1d329180517457c4dbadef47..6b5a3e79daecefd8a5898d593e661ccf932012da 100644
--- a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java
+++ b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java
@@ -12,6 +12,9 @@
 import net.sf.fmj.media.*;
 import org.jitsi.impl.neomedia.codec.*;
 import org.jitsi.service.neomedia.codec.*;
+import org.jitsi.service.neomedia.control.*;
+
+import java.awt.*;
 
 /**
  * Implements an Opus decoder.
@@ -20,6 +23,7 @@
  */
 public class JNIDecoder
     extends AbstractCodecExt
+    implements FECDecoderControl
 {
     /**
      * The list of <tt>Format</tt>s of audio data supported as input by
@@ -49,7 +53,7 @@ public class JNIDecoder
     static
     {
         SUPPORTED_INPUT_FORMATS
-	    = new Format[] {new AudioFormat(Constants.OPUS_RTP)};
+                = new Format[] {new AudioFormat(Constants.OPUS_RTP)};
     }
 
     /**
@@ -67,6 +71,23 @@ public class JNIDecoder
      */
     private int outputSamplingRate = 48000;
 
+    /**
+     * Sequence number of the last packet processed
+     */
+    private long lastPacketSeq;
+
+    /**
+     * Whether at least one packet has already been processed. Use this to
+     * prevent FEC data from trying to be decoded from the first packet in a
+     * session.
+     */
+    private boolean firstPacketProcessed = false;
+
+    /**
+     * Number of packets decoded with FEC
+     */
+    private int nbDecodedFec = 0;
+
     /**
      * Initializes a new <tt>JNIDecoder</tt> instance.
      */
@@ -78,6 +99,8 @@ public JNIDecoder()
             SUPPORTED_OUTPUT_FORMATS);
 
         inputFormats = SUPPORTED_INPUT_FORMATS;
+
+        addControl(this);
     }
 
     /**
@@ -130,18 +153,28 @@ protected int doProcess(Buffer inputBuffer, Buffer outputBuffer)
             if (null == setInputFormat(inputFormat))
                 return BUFFER_PROCESSED_FAILED;
         }
-        inputFormat = this.inputFormat;
 
-        byte[] input = (byte[]) inputBuffer.getData();
+        boolean decodeFec = false;
+        long inputSequenceNumber = inputBuffer.getSequenceNumber();
+
+        /* Detect a missing packet, take care of wraps at 2^16 */
+        if(firstPacketProcessed &&
+              (inputSequenceNumber != lastPacketSeq + 1) &&
+              !(inputSequenceNumber == 0 && lastPacketSeq == 65535))
+            decodeFec = true;
+
+        byte[] inputData = (byte[]) inputBuffer.getData();
         int inputOffset = inputBuffer.getOffset();
         int inputLength = inputBuffer.getLength();
 
         int outputLength =  Opus.decoder_get_nb_samples(decoder,
-                input, inputOffset, inputLength) * 2 /* sizeof(short) */;
-        byte[] output = validateByteArraySize(outputBuffer, outputLength);
+                inputData, inputOffset, inputLength) * 2 /* sizeof(short) */;
+        byte[] outputData = validateByteArraySize(outputBuffer, outputLength);
 
-        int samplesCount = Opus.decode(decoder, input, inputOffset, inputLength,
-                                                output, outputLength, 0);
+        int samplesCount = Opus.decode(decoder,
+                inputData, inputOffset, inputLength,
+                outputData, outputLength,
+                decodeFec ? 1 : 0);
 
         if (samplesCount > 0)
         {
@@ -150,6 +183,8 @@ protected int doProcess(Buffer inputBuffer, Buffer outputBuffer)
             outputBuffer.setFormat(getOutputFormat());
             outputBuffer.setLength(2*samplesCount); //16bit pcm
             outputBuffer.setOffset(0);
+            if(decodeFec)
+                nbDecodedFec++;
         }
         else
         {
@@ -157,6 +192,16 @@ protected int doProcess(Buffer inputBuffer, Buffer outputBuffer)
             discardOutputBuffer(outputBuffer);
         }
 
+
+        firstPacketProcessed = true;
+
+        if(decodeFec)
+        {
+            lastPacketSeq = inputSequenceNumber - 1;
+            return BUFFER_PROCESSED_OK | INPUT_BUFFER_NOT_CONSUMED;
+        }
+
+        lastPacketSeq = inputSequenceNumber;
         return BUFFER_PROCESSED_OK;
     }
 
@@ -245,4 +290,24 @@ public Format setInputFormat(Format format)
         }
         return inputFormat;
     }
+
+    /**
+     * Returns the number of packets decoded with FEC
+     * @return
+     */
+    public int fecPacketsDecoded()
+    {
+        return nbDecodedFec;
+    }
+
+    /**
+     * Stub. Only added in order to implement the <tt>FECDecoderControl</tt>
+     * interface.
+     *
+     * @return null
+     */
+    public Component getControlComponent()
+    {
+        return null;
+    }
 }
diff --git a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java
index 013c9988dc204495d74ce53de5abaa0bea1844b0..25c2d1da288e8e62da081b9c17f2a12bc3b81632 100644
--- a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java
+++ b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java
@@ -492,7 +492,8 @@ public void setExpectedPacketLoss(int percentage)
      *
      * @return null
      */
-    public Component getControlComponent() {
+    public Component getControlComponent()
+    {
         return null;
     }
 }
diff --git a/src/org/jitsi/impl/neomedia/codec/audio/silk/JavaEncoder.java b/src/org/jitsi/impl/neomedia/codec/audio/silk/JavaEncoder.java
index 85073444e9e41b220ec3931c635b18b1cc9f11cf..e38d030820ebfeff93addb7045baad1d3c06aa14 100644
--- a/src/org/jitsi/impl/neomedia/codec/audio/silk/JavaEncoder.java
+++ b/src/org/jitsi/impl/neomedia/codec/audio/silk/JavaEncoder.java
@@ -389,7 +389,8 @@ public void setExpectedPacketLoss(int percentage)
      *
      * @return null
      */
-    public Component getControlComponent() {
+    public Component getControlComponent()
+    {
         return null;
     }
 }