typedef void (*jb_force_resynch_impl)(void *jb);
/*! \brief Empty and reset jb */
typedef void (*jb_empty_and_reset_impl)(void *jb);
+/*! \brief Check if late */
+typedef int (*jb_is_late_impl)(void *jb, long ts);
/*!
jb_remove_impl remove;
jb_force_resynch_impl force_resync;
jb_empty_and_reset_impl empty_and_reset;
+ jb_is_late_impl is_late;
};
/*!
enum {
/*! This frame contains valid timing information */
AST_FRFLAG_HAS_TIMING_INFO = (1 << 0),
+ /*! This frame has been requeued */
+ AST_FRFLAG_REQUEUED = (1 << 1),
};
struct ast_frame_subclass {
typedef void __attribute__((format(printf, 1, 2))) (*jb_output_function_t)(const char *fmt, ...);
void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg);
+/*! \brief Checks if the given time stamp is late */
+int jb_is_late(jitterbuf *jb, long ts);
+
#ifdef __cplusplus
}
#endif
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);
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[] = {
.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",
.remove = jb_remove_adaptive,
.force_resync = jb_force_resynch_adaptive,
.empty_and_reset = jb_empty_and_reset_adaptive,
+ .is_late = jb_is_late_adaptive,
}
};
}
}
+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)
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
}
}
- 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;
}
* at the end of the queue.
*/
if (AST_LIST_NEXT(f, frame_list)) {
+ struct ast_frame *cur, *multi_frame = AST_LIST_NEXT(f, frame_list);
+
+ /* Mark these frames as being re-queued */
+ for (cur = multi_frame; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ ast_set_flag(cur, AST_FRFLAG_REQUEUED);
+ }
+
if (!readq_tail) {
- ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list));
+ ast_queue_frame_head(chan, multi_frame);
} else {
- __ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail);
+ __ast_queue_frame(chan, multi_frame, 0, readq_tail);
}
- ast_frfree(AST_LIST_NEXT(f, frame_list));
+ ast_frfree(multi_frame);
AST_LIST_NEXT(f, frame_list) = NULL;
}
return fixed_jb_put(jb, data, ms, ts, now);
}
-
int fixed_jb_put(struct fixed_jb *jb, void *data, long ms, long ts, long now)
{
struct fixed_jb_frame *frame, *next, *newframe;
return FIXED_JB_OK;
}
+
+int fixed_jb_is_late(struct fixed_jb *jb, long ts)
+{
+ return jb->rxcore + jb->delay + ts < jb->next_delivery;
+}
void fixed_jb_set_force_resynch(struct fixed_jb *jb);
+/*! \brief Checks if the given time stamp is late */
+int fixed_jb_is_late(struct fixed_jb *jb, long ts);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
return JB_OK;
}
-
+int jb_is_late(jitterbuf *jb, long ts)
+{
+ return ts + jb->info.current < jb->info.next_voice_ts;
+}