]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7436: added FEC support for mod_opus
authordoancea <doancea@orange-vallee.net>
Mon, 1 Jun 2015 23:17:20 +0000 (01:17 +0200)
committerdoancea <doancea@orange-vallee.net>
Tue, 2 Jun 2015 16:36:36 +0000 (18:36 +0200)
You need an enabled jitter buffer for FEC to work.
If a packet is missing we look in the jitter buffer for the next one,
if the next packet is present we pass it to the decoder to extract
the FEC info from it. If there's no FEC inside the packet, the Opus decoder
will return PLC.

src/mod/codecs/mod_opus/mod_opus.c

index 8a950aab22bdf6a04ef1882eeb183978ab232311..fbfc1595270700db704066b1a812f8cfa571821f 100644 (file)
@@ -74,6 +74,7 @@ struct opus_context {
        OpusDecoder *decoder_object;
        uint32_t enc_frame_size;
        uint32_t dec_frame_size;
+       uint32_t counter_plc_fec;
 };
 
 struct {
@@ -338,7 +339,7 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
             
                        return SWITCH_STATUS_GENERR;
                }
-        
+               context->counter_plc_fec = 0;
        }
     
        codec->private_info = context;
@@ -352,6 +353,7 @@ static switch_status_t switch_opus_destroy(switch_codec_t *codec)
     
        if (context) {
                if (context->decoder_object) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"tried PLC or FEC %d times \n",context->counter_plc_fec);
                        opus_decoder_destroy(context->decoder_object);
                        context->decoder_object = NULL;
                }
@@ -400,9 +402,13 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
                                                                                  unsigned int *flag)
 {
        struct opus_context *context = codec->private_info;
+       switch_core_session_t *session = codec->session;
+       stfu_instance_t *jb = NULL;
+       stfu_frame_t next_frame;
        int samples = 0;
     uint32_t frame_size;
        uint32_t frame_samples;
+       uint32_t found_frame;
 
        if (!context) {
                return SWITCH_STATUS_FALSE;
@@ -411,7 +417,28 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
        frame_samples = *decoded_data_len / 2 / codec->implementation->number_of_channels;
        frame_size = frame_samples - (frame_samples % (codec->implementation->actual_samples_per_second / 400));
        
-       samples = opus_decode(context->decoder_object, (*flag & SFF_PLC) ? NULL : encoded_data, encoded_data_len, decoded_data, frame_size, !!(*flag & SFF_PLC));
+       /*FEC: shameless rip-off from mod_silk.c . OPUS only supports n+1 FEC , SILK is supposed to work with n+1, n+2*/
+       if (*flag & SFF_PLC) {
+               context->counter_plc_fec;
+               if (session) {
+                       jb = switch_core_session_get_jb(session, SWITCH_MEDIA_TYPE_AUDIO);
+               }
+               if (jb && codec->cur_frame) {
+                       found_frame = stfu_n_copy_next_frame(jb, (uint32_t)codec->cur_frame->timestamp, codec->cur_frame->seq, 1, &next_frame);
+                       if (found_frame) {
+                               samples = opus_decode(context->decoder_object, next_frame.data, next_frame.dlen, decoded_data, frame_size, 1); /* opus_decode() does PLC if there's no FEC in the packet*/
+                               if (samples < 0 ) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error (FEC): %s!\n", opus_strerror(samples));
+                                       return SWITCH_STATUS_FALSE;
+                               } else {
+                                       *decoded_data_len = samples * 2 * codec->implementation->number_of_channels;
+                                       return SWITCH_STATUS_SUCCESS;
+                               }
+                       }
+               }
+       }
+
+       samples = opus_decode(context->decoder_object, (*flag & SFF_PLC) ? NULL : encoded_data, encoded_data_len, decoded_data, frame_size, 0);
 
        if (samples < 0) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error: %s fs:%u plc:%d!\n", opus_strerror(samples), frame_size, !!(*flag & SFF_PLC));