diff --git a/include/opus.h b/include/opus.h
index f540a55e7e1f25066594876eee0871c9af2a9989..cde0f20cace7dfa9f2ec1b278282b4f7491015cb 100644
--- a/include/opus.h
+++ b/include/opus.h
@@ -399,6 +399,11 @@ OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NON
 typedef struct OpusDecoder OpusDecoder;
 
 
+/** Opus DRED state.
+  * This contains the complete state of an Opus DRED packet.
+  * It is position independent and can be freely copied.
+  * @see opus_dred_create,opus_dred_init
+  */
 typedef struct OpusDRED OpusDRED;
 
 /** Gets the size of an <code>OpusDecoder</code> structure.
@@ -514,18 +519,62 @@ OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NON
   */
 OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
 
+
+/** Gets the size of an <code>OpusDRED</code> structure.
+  * @returns The size in bytes.
+  */
 OPUS_EXPORT int opus_dred_get_size(void);
 
+/** Allocates and initializes a DRED state.
+  * @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
+  */
 OPUS_EXPORT OpusDRED *opus_dred_create(int *error);
 
+/** Frees an <code>OpusDRED</code> allocated by opus_dred_create().
+  * @param[in] st <tt>OpusDRED*</tt>: State to be freed.
+  */
 OPUS_EXPORT void opus_dred_destroy(OpusDRED *dec);
 
+/** Decode an Opus DRED packet.
+  * @param [in] dred <tt>OpusDRED*</tt>: DRED state
+  * @param [in] data <tt>char*</tt>: Input payload
+  * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload
+  * @param [in] max_dred_samples <tt>opus_int32</tt>: Maximum number of DRED samples that may be needed (if available in the packet).
+  * @param [in] sampling_rate <tt>opus_int32</tt>: Sampling rate used for max_dred_samples argument. Needs not match the actual sampling rate of the decoder.
+  * @param [in] defer_processing <tt>int</tt>: Flag (0 or 1). If set to one, the CPU-intensive part of the DRED decoding is deferred until opus_dred_process() is called.
+  * @returns Number of decoded DRED samples or @ref opus_errorcodes
+  */
 OPUS_EXPORT int opus_dred_parse(OpusDRED *dred, const unsigned char *data, opus_int32 len, opus_int32 max_dred_samples, opus_int32 sampling_rate, int defer_processing) OPUS_ARG_NONNULL(1);
 
+/** Finish decoding an Opus DRED packet. The function only needs to be called if opus_dred_parse() was called with defer_processing=1.
+  * @param [in] dred <tt>OpusDRED*</tt>: DRED state
+  * @returns @ref opus_errorcodes
+  */
 OPUS_EXPORT int opus_dred_process(OpusDRED *dred);
 
-OPUS_EXPORT int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, int dred_offset, opus_int16 *pcm, int frame_size);
-OPUS_EXPORT int opus_decoder_dred_output_float(OpusDecoder *st, OpusDRED *dred, int dred_offset, float *pcm, int frame_size);
+/** Decode audio from an Opus DRED packet with floating point output.
+  * @param [in] st <tt>OpusDecoder*</tt>: Decoder state
+  * @param [in] dred <tt>OpusDRED*</tt>: DRED state
+  * @param [in] dred_offset <tt>opus_int32</tt>: position of the redundancy to decode (in samples before the beginning of the real audio data in the packet).
+  * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
+  *  is frame_size*channels*sizeof(opus_int16)
+  * @param [in] frame_size Number of samples per channel to decode in \a pcm.
+  *  frame_size <b>must</b> be a multiple of 2.5 ms.
+  * @returns Number of decoded samples or @ref opus_errorcodes
+  */
+OPUS_EXPORT int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, opus_int32 dred_offset, opus_int16 *pcm, opus_int32 frame_size);
+
+/** Decode audio from an Opus DRED packet with floating point output.
+  * @param [in] st <tt>OpusDecoder*</tt>: Decoder state
+  * @param [in] dred <tt>OpusDRED*</tt>: DRED state
+  * @param [in] dred_offset <tt>opus_int32</tt>: position of the redundancy to decode (in samples before the beginning of the real audio data in the packet).
+  * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
+  *  is frame_size*channels*sizeof(float)
+  * @param [in] frame_size Number of samples per channel to decode in \a pcm.
+  *  frame_size <b>must</b> be a multiple of 2.5 ms.
+  * @returns Number of decoded samples or @ref opus_errorcodes
+  */
+OPUS_EXPORT int opus_decoder_dred_output_float(OpusDecoder *st, OpusDRED *dred, opus_int32 dred_offset, float *pcm, opus_int32 frame_size);
 
 
 /** Parse an opus packet into one or more frames.
@@ -600,7 +649,12 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned
   */
 OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
 
-OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_has_fec(const unsigned char packet[], opus_int32 len);
+/** Checks whether an Opus packet has LBRR.
+  * @param [in] data <tt>char*</tt>: Opus packet
+  * @returns 1 is LBRR is present, 0 otherwise
+  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_has_lbrr(const unsigned char packet[], opus_int32 len);
 
 /** Gets the number of samples of an Opus packet.
   * @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
diff --git a/src/opus_decoder.c b/src/opus_decoder.c
index 93dc403606f61526b816e69e464af1c83b75eb84..8d529ceee532d7952b091d2c2000f5ceb69f9b6f 100644
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -659,7 +659,7 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
       needed_feature_frames = features_per_frame;
       if (!silk_dec->sPLC.pre_filled) needed_feature_frames+=2;
       for (i=0;i<needed_feature_frames;i++) {
-         int feature_offset = (needed_feature_frames-i-1 + (dred_offset-1)*features_per_frame);
+         int feature_offset = (needed_feature_frames-i-1 + (dred_offset/(st->Fs/100)-1)*features_per_frame);
          if (feature_offset <= 4*dred->nb_latents-1) {
            lpcnet_plc_fec_add(silk_dec->sPLC.lpcnet, dred->fec_features+feature_offset*DRED_NUM_FEATURES);
          } else {
@@ -1055,7 +1055,7 @@ int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len,
       return samples;
 }
 
-int opus_packet_has_fec(const unsigned char packet[], opus_int32 len)
+int opus_packet_has_lbrr(const unsigned char packet[], opus_int32 len)
 {
    int ret;
    const unsigned char *frames[48];
@@ -1073,7 +1073,7 @@ int opus_packet_has_fec(const unsigned char packet[], opus_int32 len)
    packet_stream_channels = opus_packet_get_nb_channels(packet);
    ret = opus_packet_parse(packet, len, NULL, frames, size, NULL);
    if (ret <= 0)
-      return 0;
+      return ret;
    lbrr = (frames[0][0] >> (7-nb_frames)) & 0x1;
    if (packet_stream_channels == 2)
       lbrr = lbrr || ((frames[0][0] >> (6-2*nb_frames)) & 0x1);
@@ -1165,12 +1165,14 @@ int opus_dred_parse(OpusDRED *dred, const unsigned char *data, opus_int32 len, o
 
 int opus_dred_process(OpusDRED *dred)
 {
+   if (dred->process_stage == 2)
+      return OPUS_OK;
    DRED_rdovae_decode_all(dred->fec_features, dred->state, dred->latents, dred->nb_latents);
    dred->process_stage = 2;
    return OPUS_OK;
 }
 
-int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, int dred_offset, opus_int16 *pcm, int frame_size)
+int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, opus_int32 dred_offset, opus_int16 *pcm, opus_int32 frame_size)
 {
    VARDECL(float, out);
    int ret, i;
@@ -1195,7 +1197,7 @@ int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, int dred_offset, o
    return ret;
 }
 
-int opus_decoder_dred_output_float(OpusDecoder *st, OpusDRED *dred, int dred_offset, float *pcm, int frame_size)
+int opus_decoder_dred_output_float(OpusDecoder *st, OpusDRED *dred, opus_int32 dred_offset, float *pcm, opus_int32 frame_size)
 {
    if(frame_size<=0)
       return OPUS_BAD_ARG;
diff --git a/src/opus_demo.c b/src/opus_demo.c
index e0c8e4d697e626fff993ffca34885993dc590e46..6c45a564a352d8867ff0d37669064bcab0976bfd 100644
--- a/src/opus_demo.c
+++ b/src/opus_demo.c
@@ -808,15 +808,12 @@ int main(int argc, char *argv[])
             /* FIXME: Figure out how to trigger the decoder when the last packet of the file is lost. */
             for (fr=0;fr<run_decoder;fr++) {
                 opus_int32 output_samples=0;
-                if (fr < lost_count-1) {
-                   opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
-                   output_samples = opus_decoder_dred_output(dec, dred, lost_count-fr, out, output_samples);
-                } else if (fr == lost_count-1 && opus_packet_has_fec(data, len)) {
+                if (fr == lost_count-1 && opus_packet_has_lbrr(data, len)) {
                    opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
                    output_samples = opus_decode(dec, data, len, out, output_samples, 1);
-                } else if (fr == lost_count-1) {
+                } else if (fr < lost_count) {
                    opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
-                   output_samples = opus_decoder_dred_output(dec, dred, 1, out, output_samples);
+                   output_samples = opus_decoder_dred_output(dec, dred, (lost_count-fr)*sampling_rate/100, out, output_samples);
                 } else {
                    output_samples = max_frame_size;
                    output_samples = opus_decode(dec, data, len, out, output_samples, 0);