From 512d849c24b3ae708fb15c86a047c56d2591ab46 Mon Sep 17 00:00:00 2001
From: Jean-Marc Valin <jmvalin@jmvalin.ca>
Date: Tue, 4 Dec 2012 14:13:46 -0500
Subject: [PATCH] Implements OPUS_GET_LAST_FRAME_DURATION decoder ctl()

---
 include/opus_defines.h         | 11 ++++++++++-
 src/opus_decoder.c             |  8 ++++++++
 src/opus_demo.c                | 10 +++++++---
 src/opus_multistream_decoder.c |  2 ++
 4 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/include/opus_defines.h b/include/opus_defines.h
index 94755f37c..cdde061a5 100644
--- a/include/opus_defines.h
+++ b/include/opus_defines.h
@@ -145,10 +145,14 @@ extern "C" {
 #define OPUS_GET_FINAL_RANGE_REQUEST         4031
 #define OPUS_GET_PITCH_REQUEST               4033
 #define OPUS_SET_GAIN_REQUEST                4034
-#define OPUS_GET_GAIN_REQUEST                4045
+#define OPUS_GET_GAIN_REQUEST                4045 /* Should have been 4035 */
 #define OPUS_SET_LSB_DEPTH_REQUEST           4036
 #define OPUS_GET_LSB_DEPTH_REQUEST           4037
 
+#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039
+
+/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
+
 /* Macros to trigger compilation errors when the wrong types are provided to a CTL */
 #define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
 #define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
@@ -516,6 +520,11 @@ extern "C" {
   *                                      24 (default: 24).
   * @hideinitializer */
 #define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the duration (in samples) of the last packet successfully decoded or concealed.
+  * @param[out] x <tt>opus_int32 *</tt>: Number of samples (at current sampling rate).
+  * @hideinitializer */
+#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)
 /**@}*/
 
 /** @defgroup opus_genericctls Generic CTLs
diff --git a/src/opus_decoder.c b/src/opus_decoder.c
index 015ae17aa..67e8cdb54 100644
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -64,6 +64,7 @@ struct OpusDecoder {
    int          prev_mode;
    int          frame_size;
    int          prev_redundancy;
+   int          last_packet_duration;
 
    opus_uint32  rangeFinal;
 };
@@ -813,6 +814,7 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
    }
    if (packet_offset != NULL)
       *packet_offset = tot_offset;
+   st->last_packet_duration = nb_samples;
    return nb_samples;
 }
 
@@ -966,6 +968,12 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
        st->decode_gain = value;
    }
    break;
+   case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
+   {
+      opus_uint32 *value = va_arg(ap, opus_uint32*);
+      *value = st->last_packet_duration;
+   }
+   break;
    default:
       /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
       ret = OPUS_UNIMPLEMENTED;
diff --git a/src/opus_demo.c b/src/opus_demo.c
index 1cb153a87..09b12a333 100644
--- a/src/opus_demo.c
+++ b/src/opus_demo.c
@@ -684,18 +684,22 @@ int main(int argc, char *argv[])
         } else {
             int output_samples;
             lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc);
+            if (lost)
+               opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
+            else
+               output_samples = max_frame_size;
             if( count >= use_inbandfec ) {
                 /* delay by one packet when using in-band FEC */
                 if( use_inbandfec  ) {
                     if( lost_prev ) {
                         /* attempt to decode with in-band FEC from next packet */
-                        output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, max_frame_size, 1);
+                        output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 1);
                     } else {
                         /* regular decode */
-                        output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, max_frame_size, 0);
+                        output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, output_samples, 0);
                     }
                 } else {
-                    output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, max_frame_size, 0);
+                    output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 0);
                 }
                 if (output_samples>0)
                 {
diff --git a/src/opus_multistream_decoder.c b/src/opus_multistream_decoder.c
index ed7cb5590..7564c7355 100644
--- a/src/opus_multistream_decoder.c
+++ b/src/opus_multistream_decoder.c
@@ -384,6 +384,8 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
    {
        case OPUS_GET_BANDWIDTH_REQUEST:
        case OPUS_GET_SAMPLE_RATE_REQUEST:
+       case OPUS_GET_GAIN_REQUEST:
+       case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
        {
           OpusDecoder *dec;
           /* For int32* GET params, just query the first stream */
-- 
GitLab