CI: Various updates to buildAsterisk.sh
[asterisk/asterisk.git] / main / abstract_jb.c
index 3baa344..b375739 100644 (file)
@@ -35,8 +35,6 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include "asterisk/frame.h"
 #include "asterisk/channel.h"
 #include "asterisk/term.h"
@@ -67,6 +65,7 @@ static long jb_next_fixed(void *jb);
 static int jb_remove_fixed(void *jb, struct ast_frame **fout);
 static void jb_force_resynch_fixed(void *jb);
 static void jb_empty_and_reset_fixed(void *jb);
+static int jb_is_late_fixed(void *jb, long ts);
 /* adaptive */
 static void * jb_create_adaptive(struct ast_jb_conf *general_config);
 static void jb_destroy_adaptive(void *jb);
@@ -77,6 +76,7 @@ static long jb_next_adaptive(void *jb);
 static int jb_remove_adaptive(void *jb, struct ast_frame **fout);
 static void jb_force_resynch_adaptive(void *jb);
 static void jb_empty_and_reset_adaptive(void *jb);
+static int jb_is_late_adaptive(void *jb, long ts);
 
 /* Available jb implementations */
 static const struct ast_jb_impl avail_impl[] = {
@@ -92,6 +92,7 @@ static const struct ast_jb_impl avail_impl[] = {
                .remove = jb_remove_fixed,
                .force_resync = jb_force_resynch_fixed,
                .empty_and_reset = jb_empty_and_reset_fixed,
+               .is_late = jb_is_late_fixed,
        },
        {
                .name = "adaptive",
@@ -105,6 +106,7 @@ static const struct ast_jb_impl avail_impl[] = {
                .remove = jb_remove_adaptive,
                .force_resync = jb_force_resynch_adaptive,
                .empty_and_reset = jb_empty_and_reset_adaptive,
+               .is_late = jb_is_late_adaptive,
        }
 };
 
@@ -284,7 +286,7 @@ int ast_jb_put(struct ast_channel *chan, struct ast_frame *f)
        /* We consider an enabled jitterbuffer should receive frames with valid timing info. */
        if (!ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO) || f->len < 2 || f->ts < 0) {
                ast_log(LOG_WARNING, "%s received frame with invalid timing info: "
-                       "has_timing_info=%d, len=%ld, ts=%ld, src=%s\n",
+                       "has_timing_info=%u, len=%ld, ts=%ld, src=%s\n",
                        ast_channel_name(chan), ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO), f->len, f->ts, f->src);
                return -1;
        }
@@ -360,7 +362,7 @@ static void jb_get_and_deliver(struct ast_channel *chan)
        }
 
        while (now >= jb->next) {
-               interpolation_len = ast_codec_interp_len(&jb->last_format);
+               interpolation_len = ast_format_get_default_ms(jb->last_format);
 
                res = jbimpl->get(jbobj, &f, now, interpolation_len);
 
@@ -371,13 +373,13 @@ static void jb_get_and_deliver(struct ast_channel *chan)
                case AST_JB_IMPL_DROP:
                        jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
                                now, jb_get_actions[res], f->ts, f->len);
-                       ast_format_copy(&jb->last_format, &f->subclass.format);
+                       ao2_replace(jb->last_format, f->subclass.format);
                        ast_frfree(f);
                        break;
                case AST_JB_IMPL_INTERP:
                        /* interpolate a frame */
                        f = &finterp;
-                       ast_format_copy(&f->subclass.format, &jb->last_format);
+                       f->subclass.format = jb->last_format;
                        f->samples  = interpolation_len * 8;
                        f->src  = "JB interpolation";
                        f->delivery = ast_tvadd(jb->timebase, ast_samp2tv(jb->next, 1000));
@@ -437,11 +439,11 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
        jb->next = jbimpl->next(jbobj);
 
        /* Init last format for a first time. */
-       ast_format_copy(&jb->last_format, &frr->subclass.format);
+       jb->last_format = ao2_bump(frr->subclass.format);
 
        /* Create a frame log file */
        if (ast_test_flag(jbconf, AST_JB_LOG)) {
-               RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(chan), ast_channel_cleanup);
+               struct ast_channel *bridged = ast_channel_bridge_peer(chan);
                char safe_logfile[30] = "/tmp/logfile-XXXXXX";
                int safe_fd;
 
@@ -477,6 +479,8 @@ static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
                        jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n",
                                now, frr->ts, frr->len);
                }
+
+               ast_channel_cleanup(bridged);
        }
 
        ast_verb(3, "%s jitterbuffer created on channel %s\n", jbimpl->name, ast_channel_name(chan));
@@ -502,6 +506,8 @@ void ast_jb_destroy(struct ast_channel *chan)
                jb->logfile = NULL;
        }
 
+       ao2_cleanup(jb->last_format);
+
        if (ast_test_flag(jb, JB_CREATED)) {
                /* Remove and free all frames still queued in jb */
                while (jbimpl->remove(jbobj, &f) == AST_JB_IMPL_OK) {
@@ -656,7 +662,7 @@ static int jb_put_fixed(void *jb, struct ast_frame *fin, long now)
 static int jb_get_fixed(void *jb, struct ast_frame **fout, long now, long interpl)
 {
        struct fixed_jb *fixedjb = (struct fixed_jb *) jb;
-       struct fixed_jb_frame frame;
+       struct fixed_jb_frame frame = { .data = &ast_null_frame };
        int res;
 
        res = fixed_jb_get(fixedjb, &frame, now, interpl);
@@ -704,6 +710,11 @@ static void jb_empty_and_reset_fixed(void *jb)
        }
 }
 
+static int jb_is_late_fixed(void *jb, long ts)
+{
+       return fixed_jb_is_late(jb, ts);
+}
+
 /* adaptive */
 
 static void *jb_create_adaptive(struct ast_jb_conf *general_config)
@@ -752,7 +763,7 @@ static int jb_put_adaptive(void *jb, struct ast_frame *fin, long now)
 static int jb_get_adaptive(void *jb, struct ast_frame **fout, long now, long interpl)
 {
        jitterbuf *adaptivejb = (jitterbuf *) jb;
-       jb_frame frame;
+       jb_frame frame = { .data = &ast_null_frame };
        int res;
 
        res = jb_get(adaptivejb, &frame, now, interpl);
@@ -810,6 +821,11 @@ const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type)
        return NULL;
 }
 
+static int jb_is_late_adaptive(void *jb, long ts)
+{
+       return jb_is_late(jb, ts);
+}
+
 #define DEFAULT_TIMER_INTERVAL 20
 #define DEFAULT_SIZE  200
 #define DEFAULT_TARGET_EXTRA  40
@@ -820,7 +836,7 @@ struct jb_framedata {
        const struct ast_jb_impl *jb_impl;
        struct ast_jb_conf jb_conf;
        struct timeval start_tv;
-       struct ast_format last_format;
+       struct ast_format *last_format;
        struct ast_timer *timer;
        int timer_interval; /* ms between deliveries */
        int timer_fd;
@@ -842,6 +858,7 @@ static void jb_framedata_destroy(struct jb_framedata *framedata)
                framedata->jb_impl->destroy(framedata->jb_obj);
                framedata->jb_obj = NULL;
        }
+       ao2_cleanup(framedata->last_format);
        ast_free(framedata);
 }
 
@@ -892,7 +909,22 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram
                }
        }
 
-       if (!frame) {
+       /*
+        * If the frame has been requeued (for instance when the translate core returns
+        * more than one frame) then if the frame is late we want to immediately return
+        * it. Otherwise attempt to insert it into the jitterbuffer.
+        *
+        * If the frame is requeued and late then in all likely hood it's a frame that
+        * that was previously retrieved from the jitterbuffer, passed to the translate
+        * core, and then put back into the channel read queue. Even if it had not been
+        * in the jitterbuffer prior to now it needs to be the next frame "out".
+        *
+        * However late arriving frames that have not been requeued (i.e. regular frames)
+        * need to be passed to the jitterbuffer so they can be appropriately dropped. As
+        * well any requeued frames that are not late should be put into the jitterbuffer.
+        */
+       if (!frame || (ast_test_flag(frame, AST_FRFLAG_REQUEUED) &&
+                      framedata->jb_impl->is_late(framedata->jb_obj, frame->ts))) {
                return frame;
        }
 
@@ -909,7 +941,7 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram
                }
 
                jbframe = ast_frisolate(frame);
-               ast_format_copy(&framedata->last_format, &frame->subclass.format);
+               ao2_replace(framedata->last_format, frame->subclass.format);
 
                if (frame->len && (frame->len != framedata->timer_interval)) {
                        framedata->timer_interval = frame->len;
@@ -921,8 +953,14 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram
                } else {
                        res = framedata->jb_impl->put(framedata->jb_obj, jbframe, now);
                }
+
                if (res == AST_JB_IMPL_OK) {
+                       if (jbframe != frame) {
+                               ast_frfree(frame);
+                       }
                        frame = &ast_null_frame;
+               } else if (jbframe != frame) {
+                       ast_frfree(jbframe);
                }
                putframe = 1;
        }
@@ -949,6 +987,8 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram
                        }
                }
 
+               ast_frfree(frame);
+               frame = &ast_null_frame;
                res = framedata->jb_impl->get(framedata->jb_obj, &frame, now, framedata->timer_interval);
                switch (res) {
                case AST_JB_IMPL_OK:
@@ -959,20 +999,23 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram
                        frame = &ast_null_frame;
                        break;
                case AST_JB_IMPL_INTERP:
-                       if (framedata->last_format.id) {
+                       if (framedata->last_format) {
                                struct ast_frame tmp = { 0, };
+
                                tmp.frametype = AST_FRAME_VOICE;
-                               ast_format_copy(&tmp.subclass.format, &framedata->last_format);
+                               tmp.subclass.format = framedata->last_format;
                                /* example: 8000hz / (1000 / 20ms) = 160 samples */
-                               tmp.samples = ast_format_rate(&framedata->last_format) / (1000 / framedata->timer_interval);
+                               tmp.samples = ast_format_get_sample_rate(framedata->last_format) / (1000 / framedata->timer_interval);
                                tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000));
                                tmp.offset = AST_FRIENDLY_OFFSET;
                                tmp.src  = "func_jitterbuffer interpolation";
+                               ast_frfree(frame);
                                frame = ast_frdup(&tmp);
                                break;
                        }
                        /* else fall through */
                case AST_JB_IMPL_NOFRAME:
+                       ast_frfree(frame);
                        frame = &ast_null_frame;
                        break;
                }
@@ -1052,6 +1095,7 @@ void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_co
                        id = datastore->data;
                        ast_framehook_detach(chan, *id);
                        ast_channel_datastore_remove(chan, datastore);
+                       ast_datastore_free(datastore);
                }
                ast_channel_unlock(chan);
                return;
@@ -1084,6 +1128,7 @@ void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_co
                        id = datastore->data;
                        ast_framehook_detach(chan, *id);
                        ast_channel_datastore_remove(chan, datastore);
+                       ast_datastore_free(datastore);
                }
 
                if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) {
@@ -1109,6 +1154,4 @@ void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_co
                framedata = NULL;
        }
        ast_channel_unlock(chan);
-
-       return;
 }