summaryrefslogtreecommitdiffstats
path: root/tinyDAV/src/audio/tdav_jitterbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinyDAV/src/audio/tdav_jitterbuffer.c')
-rwxr-xr-xtinyDAV/src/audio/tdav_jitterbuffer.c1486
1 files changed, 760 insertions, 726 deletions
diff --git a/tinyDAV/src/audio/tdav_jitterbuffer.c b/tinyDAV/src/audio/tdav_jitterbuffer.c
index 4fd1010..b2cd287 100755
--- a/tinyDAV/src/audio/tdav_jitterbuffer.c
+++ b/tinyDAV/src/audio/tdav_jitterbuffer.c
@@ -36,8 +36,8 @@
#include <string.h>
#include <limits.h>
-#define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
-#define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
+#define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
+#define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
#define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
//public functions
@@ -47,38 +47,40 @@ void jb_reset_all(jitterbuffer *jb);
void jb_destroy(jitterbuffer *jb);
void jb_set_settings(jitterbuffer *jb, jb_settings *settings);
-void jb_get_info(jitterbuffer *jb, jb_info *stats);
-void jb_get_settings(jitterbuffer *jb, jb_settings *settings);
-float jb_guess_mos(float p, long d, int codec);
+void jb_get_info(jitterbuffer *jb, jb_info *stats);
+void jb_get_settings(jitterbuffer *jb, jb_settings *settings);
+float jb_guess_mos(float p, long d, int codec);
int jb_has_frames(jitterbuffer *jb);
-void jb_put(jitterbuffer *jb, void *data, int type, long ms, long ts, long now, int codec);
+void jb_put(jitterbuffer *jb, void *data, int type, long ms, long ts, long now, int codec);
int jb_get(jitterbuffer *jb, void **data, long now, long interpl);
//private functions
-static void set_default_settings(jitterbuffer *jb);
-static void reset(jitterbuffer *jb);
-static long find_pointer(long *array, long max_index, long value); static void frame_free(jb_frame *frame);
-
-static void put_control(jitterbuffer *jb, void *data, int type, long ts);
-static void put_voice(jitterbuffer *jb, void *data, int type, long ms, long ts, int codec);
-static void put_history(jitterbuffer *jb, long ts, long now, long ms, int codec);
+static void set_default_settings(jitterbuffer *jb);
+static void reset(jitterbuffer *jb);
+static long find_pointer(long *array, long max_index, long value);
+static void frame_free(jb_frame *frame);
+
+static void put_control(jitterbuffer *jb, void *data, int type, long ts);
+static void put_voice(jitterbuffer *jb, void *data, int type, long ms, long ts, int codec);
+static void put_history(jitterbuffer *jb, long ts, long now, long ms, int codec);
static void calculate_info(jitterbuffer *jb, long ts, long now, int codec);
-static int get_control(jitterbuffer *jb, void **data);
-static int get_voice(jitterbuffer *jb, void **data, long now, long interpl);
+static int get_control(jitterbuffer *jb, void **data);
+static int get_voice(jitterbuffer *jb, void **data, long now, long interpl);
static int get_voicecase(jitterbuffer *jb, void **data, long now, long interpl, long diff);
-static int get_next_frametype(jitterbuffer *jb, long ts);
-static long get_next_framets(jitterbuffer *jb);
-static jb_frame *get_frame(jitterbuffer *jb, long ts);
+static int get_next_frametype(jitterbuffer *jb, long ts);
+static long get_next_framets(jitterbuffer *jb);
+static jb_frame *get_frame(jitterbuffer *jb, long ts);
static jb_frame *get_all_frames(jitterbuffer *jb);
//debug...
-static jb_output_function_t warnf, errf, dbgf;
-void jb_setoutput(jb_output_function_t warn, jb_output_function_t err, jb_output_function_t dbg) {
+static jb_output_function_t warnf, errf, dbgf;
+void jb_setoutput(jb_output_function_t warn, jb_output_function_t err, jb_output_function_t dbg)
+{
warnf = warn;
errf = err;
dbgf = dbg;
@@ -90,74 +92,74 @@ void jb_setoutput(jb_output_function_t warn, jb_output_function_t err, jb_output
* return NULL if malloc doesn't work
* else return jb with default_settings.
*/
-jitterbuffer *jb_new()
+jitterbuffer *jb_new()
{
- jitterbuffer *jb;
-
- jb_dbg("N");
- jb = tsk_calloc(1, sizeof(jitterbuffer));
- if (!jb) {
- jb_err("cannot allocate jitterbuffer\n");
- return NULL;
- }
- set_default_settings(jb);
- reset(jb);
- return jb;
+ jitterbuffer *jb;
+
+ jb_dbg("N");
+ jb = tsk_calloc(1, sizeof(jitterbuffer));
+ if (!jb) {
+ jb_err("cannot allocate jitterbuffer\n");
+ return NULL;
+ }
+ set_default_settings(jb);
+ reset(jb);
+ return jb;
}
/***********
- * empty voice messages
- * reset statistics
+ * empty voice messages
+ * reset statistics
* keep the settings
*/
-void jb_reset(jitterbuffer *jb)
+void jb_reset(jitterbuffer *jb)
{
- jb_frame *frame;
-
- jb_dbg("R");
- if (jb == NULL) {
- jb_err("no jitterbuffer in jb_reset()\n");
- return;
- }
-
- //free voice
- while(jb->voiceframes) {
- frame = get_all_frames(jb);
- frame_free(frame);
- }
- //reset stats
- memset(&(jb->info),0,sizeof(jb_info) );
- // set default settings
- reset(jb);
+ jb_frame *frame;
+
+ jb_dbg("R");
+ if (jb == NULL) {
+ jb_err("no jitterbuffer in jb_reset()\n");
+ return;
+ }
+
+ //free voice
+ while(jb->voiceframes) {
+ frame = get_all_frames(jb);
+ frame_free(frame);
+ }
+ //reset stats
+ memset(&(jb->info),0,sizeof(jb_info) );
+ // set default settings
+ reset(jb);
}
/***********
* empty nonvoice messages
* empty voice messages
- * reset statistics
+ * reset statistics
* reset settings to default
*/
-void jb_reset_all(jitterbuffer *jb)
+void jb_reset_all(jitterbuffer *jb)
{
- jb_frame *frame;
-
- jb_dbg("r");
- if (jb == NULL) {
- jb_err("no jitterbuffer in jb_reset_all()\n");
- return;
- }
-
- // free nonvoice
- while(jb->controlframes) {
- frame = jb->controlframes;
- jb->controlframes = frame->next;
- frame_free(frame);
- }
- // free voice and reset statistics is done by jb_reset
- jb_reset(jb);
- set_default_settings(jb);
+ jb_frame *frame;
+
+ jb_dbg("r");
+ if (jb == NULL) {
+ jb_err("no jitterbuffer in jb_reset_all()\n");
+ return;
+ }
+
+ // free nonvoice
+ while(jb->controlframes) {
+ frame = jb->controlframes;
+ jb->controlframes = frame->next;
+ frame_free(frame);
+ }
+ // free voice and reset statistics is done by jb_reset
+ jb_reset(jb);
+ set_default_settings(jb);
}
@@ -166,54 +168,54 @@ void jb_reset_all(jitterbuffer *jb)
* free all the [non]voice frames with reset_all
* free the jitterbuffer
*/
-void jb_destroy(jitterbuffer *jb)
+void jb_destroy(jitterbuffer *jb)
{
- jb_dbg("D");
- if (jb == NULL) {
- jb_err("no jitterbuffer in jb_destroy()\n");
- return;
- }
-
- jb_reset_all(jb);
- free(jb);
+ jb_dbg("D");
+ if (jb == NULL) {
+ jb_err("no jitterbuffer in jb_destroy()\n");
+ return;
+ }
+
+ jb_reset_all(jb);
+ free(jb);
}
/***********
- * Set settings for the jitterbuffer.
+ * Set settings for the jitterbuffer.
* Only if a setting is defined it will be written
* in the jb->settings.
* This means that no setting can be set to zero
*/
-void jb_set_settings(jitterbuffer *jb, jb_settings *settings)
+void jb_set_settings(jitterbuffer *jb, jb_settings *settings)
{
- jb_dbg("S");
- if (jb == NULL) {
- jb_err("no jitterbuffer in jb_set_settings()\n");
- return;
- }
-
- if (settings->min_jb) {
- jb->settings.min_jb = settings->min_jb;
- }
- if (settings->max_jb) {
- jb->settings.max_jb = settings->max_jb;
- }
- if (settings->max_successive_interp) {
- jb->settings.max_successive_interp = settings->max_successive_interp;
- }
- if (settings->extra_delay) {
- jb->settings.extra_delay = settings->extra_delay;
- }
- if (settings->wait_grow) {
- jb->settings.wait_grow = settings->wait_grow;
- }
- if (settings->wait_shrink) {
- jb->settings.wait_shrink = settings->wait_shrink;
- }
- if (settings->max_diff) {
- jb->settings.max_diff = settings->max_diff;
- }
+ jb_dbg("S");
+ if (jb == NULL) {
+ jb_err("no jitterbuffer in jb_set_settings()\n");
+ return;
+ }
+
+ if (settings->min_jb) {
+ jb->settings.min_jb = settings->min_jb;
+ }
+ if (settings->max_jb) {
+ jb->settings.max_jb = settings->max_jb;
+ }
+ if (settings->max_successive_interp) {
+ jb->settings.max_successive_interp = settings->max_successive_interp;
+ }
+ if (settings->extra_delay) {
+ jb->settings.extra_delay = settings->extra_delay;
+ }
+ if (settings->wait_grow) {
+ jb->settings.wait_grow = settings->wait_grow;
+ }
+ if (settings->wait_shrink) {
+ jb->settings.wait_shrink = settings->wait_shrink;
+ }
+ if (settings->max_diff) {
+ jb->settings.max_diff = settings->max_diff;
+ }
}
@@ -223,34 +225,35 @@ void jb_set_settings(jitterbuffer *jb, jb_settings *settings)
* delay and delay_target will be calculated
* *stats = info
*/
-void jb_get_info(jitterbuffer *jb, jb_info *stats)
+void jb_get_info(jitterbuffer *jb, jb_info *stats)
{
- long max_index, pointer;
-
- jb_dbg("I");
- if (jb == NULL) {
- jb_err("no jitterbuffer in jb_get_info()\n");
- return;
- }
-
- jb->info.delay = jb->current - jb->min;
- jb->info.delay_target = jb->target - jb->min;
-
- //calculate the losspct...
- max_index = (jb->hist_pointer < JB_HISTORY_SIZE) ?
-jb->hist_pointer : JB_HISTORY_SIZE-1;
- if (max_index>1) {
- pointer = find_pointer(&jb->hist_sorted_delay[0], max_index,
-jb->current);
- jb->info.losspct = ((max_index - pointer)*100/max_index);
- if (jb->info.losspct < 0) {
- jb->info.losspct = 0;
- }
- } else {
- jb->info.losspct = 0;
- }
-
- *stats = jb->info;
+ long max_index, pointer;
+
+ jb_dbg("I");
+ if (jb == NULL) {
+ jb_err("no jitterbuffer in jb_get_info()\n");
+ return;
+ }
+
+ jb->info.delay = jb->current - jb->min;
+ jb->info.delay_target = jb->target - jb->min;
+
+ //calculate the losspct...
+ max_index = (jb->hist_pointer < JB_HISTORY_SIZE) ?
+ jb->hist_pointer : JB_HISTORY_SIZE-1;
+ if (max_index>1) {
+ pointer = find_pointer(&jb->hist_sorted_delay[0], max_index,
+ jb->current);
+ jb->info.losspct = ((max_index - pointer)*100/max_index);
+ if (jb->info.losspct < 0) {
+ jb->info.losspct = 0;
+ }
+ }
+ else {
+ jb->info.losspct = 0;
+ }
+
+ *stats = jb->info;
}
@@ -258,56 +261,56 @@ jb->current);
* gives the settings for this jitterbuffer
* *settings = settings
*/
-void jb_get_settings(jitterbuffer *jb, jb_settings *settings)
+void jb_get_settings(jitterbuffer *jb, jb_settings *settings)
{
- jb_dbg("S");
- if (jb == NULL) {
- jb_err("no jitterbuffer in jb_get_settings()\n");
- return;
- }
-
- *settings = jb->settings;
+ jb_dbg("S");
+ if (jb == NULL) {
+ jb_err("no jitterbuffer in jb_get_settings()\n");
+ return;
+ }
+
+ *settings = jb->settings;
}
/***********
- * returns an estimate on the MOS with given loss, delay and codec
+ * returns an estimate on the MOS with given loss, delay and codec
* if the formula is not present the default will be used
* please use the JB_CODEC_OTHER if you want to define your own formula
- *
+ *
*/
-float jb_guess_mos(float p, long d, int codec)
+float jb_guess_mos(float p, long d, int codec)
{
- float result;
-
- switch (codec) {
- case JB_CODEC_GSM_EFR:
- result = (4.31f - 0.23f*p - 0.0071f*d);
- break;
-
- case JB_CODEC_G723_1:
- result = (3.99f - 0.16f*p - 0.0071f*d);
- break;
-
- case JB_CODEC_G729:
- case JB_CODEC_G729A:
- result = (4.13f - 0.14f*p - 0.0071f*d);
- break;
+ float result;
+
+ switch (codec) {
+ case JB_CODEC_GSM_EFR:
+ result = (4.31f - 0.23f*p - 0.0071f*d);
+ break;
+
+ case JB_CODEC_G723_1:
+ result = (3.99f - 0.16f*p - 0.0071f*d);
+ break;
+
+ case JB_CODEC_G729:
+ case JB_CODEC_G729A:
+ result = (4.13f - 0.14f*p - 0.0071f*d);
+ break;
case JB_CODEC_G711x_PLC:
- result = (4.42f - 0.087f*p - 0.0071f*d);
- break;
+ result = (4.42f - 0.087f*p - 0.0071f*d);
+ break;
case JB_CODEC_G711x:
- result = (4.42f - 0.63f*p - 0.0071f*d);
- break;
-
+ result = (4.42f - 0.63f*p - 0.0071f*d);
+ break;
+
case JB_CODEC_OTHER:
default:
- result = (4.42f - 0.63f*p - 0.0071f*d);
+ result = (4.42f - 0.63f*p - 0.0071f*d);
- }
- return result;
+ }
+ return result;
}
@@ -316,69 +319,74 @@ float jb_guess_mos(float p, long d, int codec)
*/
int jb_has_frames(jitterbuffer *jb)
{
- jb_dbg("H");
- if (jb == NULL) {
- jb_err("no jitterbuffer in jb_has_frames()\n");
- return JB_NOJB;
- }
-
- if(jb->controlframes || jb->voiceframes) {
- return JB_OK;
- } else {
- return JB_EMPTY;
- }
+ jb_dbg("H");
+ if (jb == NULL) {
+ jb_err("no jitterbuffer in jb_has_frames()\n");
+ return JB_NOJB;
+ }
+
+ if(jb->controlframes || jb->voiceframes) {
+ return JB_OK;
+ }
+ else {
+ return JB_EMPTY;
+ }
}
/***********
- * Put a packet into the jitterbuffers
+ * Put a packet into the jitterbuffers
* Only the timestamps of voicepackets are put in the history
* this because the jitterbuffer only works for voicepackets
* don't put packets twice in history and queue (e.g. transmitting every frame twice)
* keep track of statistics
*/
-void jb_put(jitterbuffer *jb, void *data, int type, long ms, long ts, long now, int codec)
-{
- long pointer, max_index;
-
- if (jb == NULL) {
- jb_err("no jitterbuffer in jb_put()\n");
- return;
- }
-
- jb->info.frames_received++;
-
- if (type == JB_TYPE_CONTROL) {
- //put the packet into the contol-queue of the jitterbuffer
- jb_dbg("pC");
- put_control(jb,data,type,ts);
-
- } else if (type == JB_TYPE_VOICE) {
- // only add voice that aren't already in the buffer
- max_index = (jb->hist_pointer < JB_HISTORY_SIZE) ? jb->hist_pointer : JB_HISTORY_SIZE-1;
- pointer = find_pointer(&jb->hist_sorted_timestamp[0], max_index, ts);
- if (jb->hist_sorted_timestamp[pointer]==ts) { //timestamp already in queue
- jb_dbg("pT");
- free(data);
- jb->info.frames_dropped_twice++;
- } else { //add
- jb_dbg("pV");
- /* add voicepacket to history */
- put_history(jb,ts,now,ms,codec);
- /*calculate jitterbuffer size*/
- calculate_info(jb, ts, now, codec);
- /*put the packet into the queue of the jitterbuffer*/
- put_voice(jb,data,type,ms,ts,codec);
- }
-
- } else if (type == JB_TYPE_SILENCE){ //silence
- jb_dbg("pS");
- put_voice(jb,data,type,ms,ts,codec);
-
- } else {//should NEVER happen
- jb_err("jb_put(): type not known\n");
- free(data);
- }
+void jb_put(jitterbuffer *jb, void *data, int type, long ms, long ts, long now, int codec)
+{
+ long pointer, max_index;
+
+ if (jb == NULL) {
+ jb_err("no jitterbuffer in jb_put()\n");
+ return;
+ }
+
+ jb->info.frames_received++;
+
+ if (type == JB_TYPE_CONTROL) {
+ //put the packet into the contol-queue of the jitterbuffer
+ jb_dbg("pC");
+ put_control(jb,data,type,ts);
+
+ }
+ else if (type == JB_TYPE_VOICE) {
+ // only add voice that aren't already in the buffer
+ max_index = (jb->hist_pointer < JB_HISTORY_SIZE) ? jb->hist_pointer : JB_HISTORY_SIZE-1;
+ pointer = find_pointer(&jb->hist_sorted_timestamp[0], max_index, ts);
+ if (jb->hist_sorted_timestamp[pointer]==ts) { //timestamp already in queue
+ jb_dbg("pT");
+ free(data);
+ jb->info.frames_dropped_twice++;
+ }
+ else { //add
+ jb_dbg("pV");
+ /* add voicepacket to history */
+ put_history(jb,ts,now,ms,codec);
+ /*calculate jitterbuffer size*/
+ calculate_info(jb, ts, now, codec);
+ /*put the packet into the queue of the jitterbuffer*/
+ put_voice(jb,data,type,ms,ts,codec);
+ }
+
+ }
+ else if (type == JB_TYPE_SILENCE) { //silence
+ jb_dbg("pS");
+ put_voice(jb,data,type,ms,ts,codec);
+
+ }
+ else { //should NEVER happen
+ jb_err("jb_put(): type not known\n");
+ free(data);
+ }
}
@@ -389,48 +397,48 @@ void jb_put(jitterbuffer *jb, void *data, int type, long ms, long ts, long now,
* returns JB_INTERP if interpolating is required
* returns JB_EMPTY if no voice frame is in the jitterbuffer (only during silence)
*/
-int jb_get(jitterbuffer *jb, void **data, long now, long interpl)
+int jb_get(jitterbuffer *jb, void **data, long now, long interpl)
{
- int result;
-
- jb_dbg("A");
- if (jb == NULL) {
- jb_err("no jitterbuffer in jb_get()\n");
- return JB_NOJB;
- }
-
- result = get_control(jb, data);
- if (result != JB_OK ) { //no control message available maybe there is voice...
- result = get_voice(jb, data, now, interpl);
- }
- return result;
+ int result;
+
+ jb_dbg("A");
+ if (jb == NULL) {
+ jb_err("no jitterbuffer in jb_get()\n");
+ return JB_NOJB;
+ }
+
+ result = get_control(jb, data);
+ if (result != JB_OK ) { //no control message available maybe there is voice...
+ result = get_voice(jb, data, now, interpl);
+ }
+ return result;
}
/***********
- * set all the settings to default
+ * set all the settings to default
*/
-static void set_default_settings(jitterbuffer *jb)
+static void set_default_settings(jitterbuffer *jb)
{
- jb->settings.min_jb = JB_MIN_SIZE;
- jb->settings.max_jb = JB_MAX_SIZE;
- jb->settings.max_successive_interp = JB_MAX_SUCCESSIVE_INTERP;
- jb->settings.extra_delay = JB_ALLOW_EXTRA_DELAY;
- jb->settings.wait_grow = JB_WAIT_GROW;
- jb->settings.wait_shrink = JB_WAIT_SHRINK;
- jb->settings.max_diff = JB_MAX_DIFF;
+ jb->settings.min_jb = JB_MIN_SIZE;
+ jb->settings.max_jb = JB_MAX_SIZE;
+ jb->settings.max_successive_interp = JB_MAX_SUCCESSIVE_INTERP;
+ jb->settings.extra_delay = JB_ALLOW_EXTRA_DELAY;
+ jb->settings.wait_grow = JB_WAIT_GROW;
+ jb->settings.wait_shrink = JB_WAIT_SHRINK;
+ jb->settings.max_diff = JB_MAX_DIFF;
}
/***********
- * reset the jitterbuffer so we can start in silence and
+ * reset the jitterbuffer so we can start in silence and
* we start with a new history
*/
static void reset(jitterbuffer *jb)
{
- jb->hist_pointer = 0; //start over
- jb->silence_begin_ts = 0; //no begin_ts defined
- jb->info.silence =1; //we always start in silence
+ jb->hist_pointer = 0; //start over
+ jb->silence_begin_ts = 0; //no begin_ts defined
+ jb->info.silence =1; //we always start in silence
}
@@ -442,214 +450,221 @@ static void reset(jitterbuffer *jb)
* if value doesn't exist return first pointer where array[low]>value
* int low; //the lowest index being examined
* int max_index; //the highest index being examined
- * int mid; //the middle index between low and max_index.
+ * int mid; //the middle index between low and max_index.
* mid ==(low+max_index)/2
* at the end low is the position of value or where array[low]>value
- */
-static long find_pointer(long *array, long max_index, long value)
+ */
+static long find_pointer(long *array, long max_index, long value)
{
- register long low, mid, high;
- low = 0;
- high = max_index;
- while (low<=high) {
- mid= (low+high)/2;
- if (array[mid] < value) {
- low = mid+1;
- } else {
- high = mid-1;
- }
- }
- while(low < max_index && (array[low]==array[(low+1)]) ) {
- low++;
- }
- return low;
+ register long low, mid, high;
+ low = 0;
+ high = max_index;
+ while (low<=high) {
+ mid= (low+high)/2;
+ if (array[mid] < value) {
+ low = mid+1;
+ }
+ else {
+ high = mid-1;
+ }
+ }
+ while(low < max_index && (array[low]==array[(low+1)]) ) {
+ low++;
+ }
+ return low;
}
/***********
* free the given frame, afterwards the framepointer is undefined
*/
-static void frame_free(jb_frame *frame)
+static void frame_free(jb_frame *frame)
{
- if (frame->data) {
- free(frame->data);
- }
- free(frame);
+ if (frame->data) {
+ free(frame->data);
+ }
+ free(frame);
}
/***********
* put a nonvoice frame into the nonvoice queue
*/
-static void put_control(jitterbuffer *jb, void *data, int type, long ts)
+static void put_control(jitterbuffer *jb, void *data, int type, long ts)
{
- jb_frame *frame, *p;
-
- frame = malloc(sizeof(jb_frame));
- if(!frame) {
- jb_err("cannot allocate frame\n");
- return;
- }
- frame->data = data;
- frame->ts = ts;
- frame->type = type;
- frame->next = NULL;
- data = NULL;//to avoid stealing memory
-
- p = jb->controlframes;
- if (p) { //there are already control messages
- if (ts < p->ts) {
- jb->controlframes = frame;
- frame->next = p;
- } else {
- while (p->next && (ts >=p->next->ts)) {//sort on timestamps! so find place to put...
- p = p->next;
- }
- if (p->next) {
- frame->next = p->next;
- }
- p->next = frame;
- }
- } else {
- jb->controlframes = frame;
- }
+ jb_frame *frame, *p;
+
+ frame = malloc(sizeof(jb_frame));
+ if(!frame) {
+ jb_err("cannot allocate frame\n");
+ return;
+ }
+ frame->data = data;
+ frame->ts = ts;
+ frame->type = type;
+ frame->next = NULL;
+ data = NULL;//to avoid stealing memory
+
+ p = jb->controlframes;
+ if (p) { //there are already control messages
+ if (ts < p->ts) {
+ jb->controlframes = frame;
+ frame->next = p;
+ }
+ else {
+ while (p->next && (ts >=p->next->ts)) {//sort on timestamps! so find place to put...
+ p = p->next;
+ }
+ if (p->next) {
+ frame->next = p->next;
+ }
+ p->next = frame;
+ }
+ }
+ else {
+ jb->controlframes = frame;
+ }
}
/***********
- * put a voice or silence frame into the jitterbuffer
+ * put a voice or silence frame into the jitterbuffer
*/
-static void put_voice(jitterbuffer *jb, void *data, int type, long ms, long ts, int codec)
+static void put_voice(jitterbuffer *jb, void *data, int type, long ms, long ts, int codec)
{
- jb_frame *frame, *p;
- frame = malloc(sizeof(jb_frame));
- if(!frame) {
- jb_err("cannot allocate frame\n");
- return;
- }
-
- frame->data = data;
- frame->ts = ts;
- frame->ms = ms;
- frame->type = type;
- frame->codec = codec;
-
- data = NULL; //to avoid stealing the memory location
- /*
- * frames are a circular list, jb->voiceframes points to to the lowest ts,
- * jb->voiceframes->prev points to the highest ts
- */
- if(!jb->voiceframes) { /* queue is empty */
- jb->voiceframes = frame;
- frame->next = frame;
- frame->prev = frame;
- } else {
- p = jb->voiceframes;
- if(ts < p->prev->ts) { //frame is out of order
- jb->info.frames_ooo++;
- }
- if (ts < p->ts) { //frame is lowest, let voiceframes point to it!
- jb->voiceframes = frame;
- } else {
- while(ts < p->prev->ts ) {
- p = p->prev;
- }
- }
- frame->next = p;
- frame->prev = p->prev;
- frame->next->prev = frame;
- frame->prev->next = frame;
- }
+ jb_frame *frame, *p;
+ frame = malloc(sizeof(jb_frame));
+ if(!frame) {
+ jb_err("cannot allocate frame\n");
+ return;
+ }
+
+ frame->data = data;
+ frame->ts = ts;
+ frame->ms = ms;
+ frame->type = type;
+ frame->codec = codec;
+
+ data = NULL; //to avoid stealing the memory location
+ /*
+ * frames are a circular list, jb->voiceframes points to to the lowest ts,
+ * jb->voiceframes->prev points to the highest ts
+ */
+ if(!jb->voiceframes) { /* queue is empty */
+ jb->voiceframes = frame;
+ frame->next = frame;
+ frame->prev = frame;
+ }
+ else {
+ p = jb->voiceframes;
+ if(ts < p->prev->ts) { //frame is out of order
+ jb->info.frames_ooo++;
+ }
+ if (ts < p->ts) { //frame is lowest, let voiceframes point to it!
+ jb->voiceframes = frame;
+ }
+ else {
+ while(ts < p->prev->ts ) {
+ p = p->prev;
+ }
+ }
+ frame->next = p;
+ frame->prev = p->prev;
+ frame->next->prev = frame;
+ frame->prev->next = frame;
+ }
}
/***********
* puts the timestamps of a received packet in the history of *jb
* for later calculations of the size of jitterbuffer *jb.
- *
- * summary of function:
- * - calculate delay difference
- * - delete old value from hist & sorted_history_delay & sorted_history_timestamp if needed
+ *
+ * summary of function:
+ * - calculate delay difference
+ * - delete old value from hist & sorted_history_delay & sorted_history_timestamp if needed
* - add new value to history & sorted_history_delay & sorted_history_timestamp
- * - we keep sorted_history_delay for calculations
+ * - we keep sorted_history_delay for calculations
* - we keep sorted_history_timestamp for ensuring each timestamp isn't put twice in the buffer.
*/
-static void put_history(jitterbuffer *jb, long ts, long now, long ms, int codec)
+static void put_history(jitterbuffer *jb, long ts, long now, long ms, int codec)
{
- jb_hist_element out, in;
- long max_index, pointer, location;
-
- // max_index is the highest possible index
- max_index = (jb->hist_pointer < JB_HISTORY_SIZE) ? jb->hist_pointer : JB_HISTORY_SIZE-1;
- location = (jb->hist_pointer % JB_HISTORY_SIZE);
-
- // we want to delete a value from the jitterbuffer
- // only when we are through the history.
- if (jb->hist_pointer > JB_HISTORY_SIZE-1) {
- /* the value we need to delete from sorted histories */
- out = jb->hist[location];
- //delete delay from hist_sorted_delay
- pointer = find_pointer(&jb->hist_sorted_delay[0], max_index, out.delay);
- /* move over pointer is the position of kicked*/
- if (pointer<max_index) { //only move if we have something to move
- memmove( &(jb->hist_sorted_delay[pointer]),
- &(jb->hist_sorted_delay[pointer+1]),
- ((JB_HISTORY_SIZE-(pointer+1)) * sizeof(long)) );
- }
-
- //delete timestamp from hist_sorted_timestamp
- pointer = find_pointer(&jb->hist_sorted_timestamp[0], max_index, out.ts);
- /* move over pointer is the position of kicked*/
- if (pointer<max_index) { //only move if we have something to move
- memmove( &(jb->hist_sorted_timestamp[pointer]),
- &(jb->hist_sorted_timestamp[pointer+1]),
- ((JB_HISTORY_SIZE-(pointer+1)) * sizeof(long)) );
- }
- }
-
- in.delay = now - ts; //delay of current packet
- in.ts = ts; //timestamp of current packet
- in.ms = ms; //length of current packet
- in.codec = codec; //codec of current packet
-
- /* adding the new delay to the sorted history
- * first special cases:
- * - delay is the first history stamp
- * - delay > highest history stamp
- */
- if (max_index==0 || in.delay >= jb->hist_sorted_delay[max_index-1]) {
- jb->hist_sorted_delay[max_index] = in.delay;
- } else {
- pointer = find_pointer(&jb->hist_sorted_delay[0], (max_index-1), in.delay);
- /* move over and add delay */
- memmove( &(jb->hist_sorted_delay[pointer+1]),
- &(jb->hist_sorted_delay[pointer]),
- ((JB_HISTORY_SIZE-(pointer+1)) * sizeof(long)) );
- jb->hist_sorted_delay[pointer] = in.delay;
- }
-
- /* adding the new timestamp to the sorted history
- * first special cases:
- * - timestamp is the first history stamp
- * - timestamp > highest history stamp
- */
- if (max_index==0 || in.ts >= jb->hist_sorted_timestamp[max_index-1]) {
- jb->hist_sorted_timestamp[max_index] = in.ts;
- } else {
-
- pointer = find_pointer(&jb->hist_sorted_timestamp[0], (max_index-1), in.ts);
- /* move over and add timestamp */
- memmove( &(jb->hist_sorted_timestamp[pointer+1]),
- &(jb->hist_sorted_timestamp[pointer]),
- ((JB_HISTORY_SIZE-(pointer+1)) * sizeof(long)) );
- jb->hist_sorted_timestamp[pointer] = in.ts;
- }
-
- /* put the jb_hist_element in the history
- * then increase hist_pointer for next time
- */
- jb->hist[location] = in;
- jb->hist_pointer++;
+ jb_hist_element out, in;
+ long max_index, pointer, location;
+
+ // max_index is the highest possible index
+ max_index = (jb->hist_pointer < JB_HISTORY_SIZE) ? jb->hist_pointer : JB_HISTORY_SIZE-1;
+ location = (jb->hist_pointer % JB_HISTORY_SIZE);
+
+ // we want to delete a value from the jitterbuffer
+ // only when we are through the history.
+ if (jb->hist_pointer > JB_HISTORY_SIZE-1) {
+ /* the value we need to delete from sorted histories */
+ out = jb->hist[location];
+ //delete delay from hist_sorted_delay
+ pointer = find_pointer(&jb->hist_sorted_delay[0], max_index, out.delay);
+ /* move over pointer is the position of kicked*/
+ if (pointer<max_index) { //only move if we have something to move
+ memmove( &(jb->hist_sorted_delay[pointer]),
+ &(jb->hist_sorted_delay[pointer+1]),
+ ((JB_HISTORY_SIZE-(pointer+1)) * sizeof(long)) );
+ }
+
+ //delete timestamp from hist_sorted_timestamp
+ pointer = find_pointer(&jb->hist_sorted_timestamp[0], max_index, out.ts);
+ /* move over pointer is the position of kicked*/
+ if (pointer<max_index) { //only move if we have something to move
+ memmove( &(jb->hist_sorted_timestamp[pointer]),
+ &(jb->hist_sorted_timestamp[pointer+1]),
+ ((JB_HISTORY_SIZE-(pointer+1)) * sizeof(long)) );
+ }
+ }
+
+ in.delay = now - ts; //delay of current packet
+ in.ts = ts; //timestamp of current packet
+ in.ms = ms; //length of current packet
+ in.codec = codec; //codec of current packet
+
+ /* adding the new delay to the sorted history
+ * first special cases:
+ * - delay is the first history stamp
+ * - delay > highest history stamp
+ */
+ if (max_index==0 || in.delay >= jb->hist_sorted_delay[max_index-1]) {
+ jb->hist_sorted_delay[max_index] = in.delay;
+ }
+ else {
+ pointer = find_pointer(&jb->hist_sorted_delay[0], (max_index-1), in.delay);
+ /* move over and add delay */
+ memmove( &(jb->hist_sorted_delay[pointer+1]),
+ &(jb->hist_sorted_delay[pointer]),
+ ((JB_HISTORY_SIZE-(pointer+1)) * sizeof(long)) );
+ jb->hist_sorted_delay[pointer] = in.delay;
+ }
+
+ /* adding the new timestamp to the sorted history
+ * first special cases:
+ * - timestamp is the first history stamp
+ * - timestamp > highest history stamp
+ */
+ if (max_index==0 || in.ts >= jb->hist_sorted_timestamp[max_index-1]) {
+ jb->hist_sorted_timestamp[max_index] = in.ts;
+ }
+ else {
+
+ pointer = find_pointer(&jb->hist_sorted_timestamp[0], (max_index-1), in.ts);
+ /* move over and add timestamp */
+ memmove( &(jb->hist_sorted_timestamp[pointer+1]),
+ &(jb->hist_sorted_timestamp[pointer]),
+ ((JB_HISTORY_SIZE-(pointer+1)) * sizeof(long)) );
+ jb->hist_sorted_timestamp[pointer] = in.ts;
+ }
+
+ /* put the jb_hist_element in the history
+ * then increase hist_pointer for next time
+ */
+ jb->hist[location] = in;
+ jb->hist_pointer++;
}
@@ -659,123 +674,128 @@ static void put_history(jitterbuffer *jb, long ts, long now, long ms, int codec)
* Adaptive Playout Buffer Algorithm for Enhancing Perceived Quality of Streaming Applications
* by: Kouhei Fujimoto & Shingo Ata & Masayuki Murata
* http://www.nal.ics.es.osaka-u.ac.jp/achievements/web2002/pdf/journal/k-fujimo02TSJ-AdaptivePlayoutBuffer.pdf
- *
+ *
* it calculates jitter and minimum delay
* get the best delay for the specified codec
-
+
*/
-static void calculate_info(jitterbuffer *jb, long ts, long now, int codec)
+static void calculate_info(jitterbuffer *jb, long ts, long now, int codec)
{
- long diff, size, max_index, d, d1, d2, n;
- float p, p1, p2, A, B;
- //size = how many items there in the history
- size = (jb->hist_pointer < JB_HISTORY_SIZE) ? jb->hist_pointer : JB_HISTORY_SIZE;
- max_index = size-1;
-
- /*
- * the Inter-Quartile Range can be used for estimating jitter
- * http://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#variable
- * just take the square root of the iqr for jitter
- */
- jb->info.iqr = jb->hist_sorted_delay[max_index*3/4] - jb->hist_sorted_delay[max_index/4];
-
-
- /*
- * The RTP way of calculating jitter.
- * This one is used at the moment, although it is not correct.
- * But in this way the other side understands us.
- */
- diff = now - ts - jb->last_delay;
- if (!jb->last_delay) {
- diff = 0; //this to make sure we won't get odd jitter due first ts.
- }
- jb->last_delay = now - ts;
- if (diff <0){
- diff = -diff;
- }
- jb->info.jitter = jb->info.jitter + (diff - jb->info.jitter)/16;
-
- /* jb->min is minimum delay in hist_sorted_delay, we don't look at the lowest 2% */
- /* because sometimes there are odd delays in there */
- jb->min = jb->hist_sorted_delay[(max_index*2/100)];
-
- /*
- * calculating the preferred size of the jitterbuffer:
- * instead of calculating the optimum delay using the Pareto equation
- * I use look at the array of sorted delays and choose my optimum from there
- * always walk trough a percentage of the history this because imagine following tail:
- * [...., 12, 300, 301 ,302]
- * her we want to discard last three but that won't happen if we won't walk the array
- * the number of frames we walk depends on how scattered the sorted delays are.
- * For that we look at the iqr. The dependencies of the iqr are based on
- * tests we've done here in the lab. But are not optimized.
- */
- //init:
- //the higest delay..
- d = d1= d2 = jb->hist_sorted_delay[max_index]- jb->min;
- A=B=LONG_MIN;
- p = p2 =0;
- n=0;
- p1 = 5; //always look at the top 5%
- if (jb->info.iqr >200) { //with more jitter look at more delays
- p1=25;
- } else if (jb->info.iqr >100) {
- p1=20;
- } else if (jb->info.iqr >50){
- p1=11;
- }
-
- //find the optimum delay..
- while(max_index>10 && (B > A ||p2<p1)) { // By MDI: from ">=" to ">"
- //the packetloss with this delay
- p2 =(n*100.0f/size);
- // estimate MOS-value
- B = jb_guess_mos(p2,d2,codec);
- if (B > A) {
- p = p2;
- d = d2;
- A = B;
- }
- d1 = d2;
- //find next delay != delay so the same delay isn't calculated twice
- //don't look further if we have seen half of the history
- while((d2>=d1) && ((n*2)<max_index) ) {
- n++;
- d2 = jb->hist_sorted_delay[(max_index-n)] - jb->min;
- }
- }
- //the targeted size of the jitterbuffer
- if (jb->settings.min_jb && (jb->settings.min_jb > d) ) {
- jb->target = jb->min + jb->settings.min_jb;
- } else if (jb->settings.max_jb && (jb->settings.max_jb > d) ){
- jb->target = jb->min + jb->settings.max_jb;
- } else {
- jb->target = jb->min + d;
- }
+ long diff, size, max_index, d, d1, d2, n;
+ float p, p1, p2, A, B;
+ //size = how many items there in the history
+ size = (jb->hist_pointer < JB_HISTORY_SIZE) ? jb->hist_pointer : JB_HISTORY_SIZE;
+ max_index = size-1;
+
+ /*
+ * the Inter-Quartile Range can be used for estimating jitter
+ * http://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#variable
+ * just take the square root of the iqr for jitter
+ */
+ jb->info.iqr = jb->hist_sorted_delay[max_index*3/4] - jb->hist_sorted_delay[max_index/4];
+
+
+ /*
+ * The RTP way of calculating jitter.
+ * This one is used at the moment, although it is not correct.
+ * But in this way the other side understands us.
+ */
+ diff = now - ts - jb->last_delay;
+ if (!jb->last_delay) {
+ diff = 0; //this to make sure we won't get odd jitter due first ts.
+ }
+ jb->last_delay = now - ts;
+ if (diff <0) {
+ diff = -diff;
+ }
+ jb->info.jitter = jb->info.jitter + (diff - jb->info.jitter)/16;
+
+ /* jb->min is minimum delay in hist_sorted_delay, we don't look at the lowest 2% */
+ /* because sometimes there are odd delays in there */
+ jb->min = jb->hist_sorted_delay[(max_index*2/100)];
+
+ /*
+ * calculating the preferred size of the jitterbuffer:
+ * instead of calculating the optimum delay using the Pareto equation
+ * I use look at the array of sorted delays and choose my optimum from there
+ * always walk trough a percentage of the history this because imagine following tail:
+ * [...., 12, 300, 301 ,302]
+ * her we want to discard last three but that won't happen if we won't walk the array
+ * the number of frames we walk depends on how scattered the sorted delays are.
+ * For that we look at the iqr. The dependencies of the iqr are based on
+ * tests we've done here in the lab. But are not optimized.
+ */
+ //init:
+ //the higest delay..
+ d = d1= d2 = jb->hist_sorted_delay[max_index]- jb->min;
+ A=B=LONG_MIN;
+ p = p2 =0;
+ n=0;
+ p1 = 5; //always look at the top 5%
+ if (jb->info.iqr >200) { //with more jitter look at more delays
+ p1=25;
+ }
+ else if (jb->info.iqr >100) {
+ p1=20;
+ }
+ else if (jb->info.iqr >50) {
+ p1=11;
+ }
+
+ //find the optimum delay..
+ while(max_index>10 && (B > A ||p2<p1)) { // By MDI: from ">=" to ">"
+ //the packetloss with this delay
+ p2 =(n*100.0f/size);
+ // estimate MOS-value
+ B = jb_guess_mos(p2,d2,codec);
+ if (B > A) {
+ p = p2;
+ d = d2;
+ A = B;
+ }
+ d1 = d2;
+ //find next delay != delay so the same delay isn't calculated twice
+ //don't look further if we have seen half of the history
+ while((d2>=d1) && ((n*2)<max_index) ) {
+ n++;
+ d2 = jb->hist_sorted_delay[(max_index-n)] - jb->min;
+ }
+ }
+ //the targeted size of the jitterbuffer
+ if (jb->settings.min_jb && (jb->settings.min_jb > d) ) {
+ jb->target = jb->min + jb->settings.min_jb;
+ }
+ else if (jb->settings.max_jb && (jb->settings.max_jb > d) ) {
+ jb->target = jb->min + jb->settings.max_jb;
+ }
+ else {
+ jb->target = jb->min + d;
+ }
}
/***********
* if there is a nonvoice frame it will be returned [*data] and the frame
* will be made free
- */
-static int get_control(jitterbuffer *jb, void **data)
+ */
+static int get_control(jitterbuffer *jb, void **data)
{
- jb_frame *frame;
- int result;
-
- frame = jb->controlframes;
- if (frame) {
- jb_dbg("gC");
- *data = frame->data;
- frame->data = NULL;
- jb->controlframes = frame->next;
- frame_free(frame);
- result = JB_OK;
- } else {
- result = JB_NOFRAME;
- }
- return result;
+ jb_frame *frame;
+ int result;
+
+ frame = jb->controlframes;
+ if (frame) {
+ jb_dbg("gC");
+ *data = frame->data;
+ frame->data = NULL;
+ jb->controlframes = frame->next;
+ frame_free(frame);
+ result = JB_OK;
+ }
+ else {
+ result = JB_NOFRAME;
+ }
+ return result;
}
@@ -784,68 +804,72 @@ static int get_control(jitterbuffer *jb, void **data)
* returns JB_NOFRAME if it's no time to play voice and or no frame available
* returns JB_INTERP if interpolating is required
* returns JB_EMPTY if no voice frame is in the jitterbuffer (only during silence)
- *
+ *
* if the next frame is a silence frame we will go in silence-mode
* each new instance of the jitterbuffer will start in silence mode
* in silence mode we will set the jitterbuffer to the size we want
- * when we are not in silence mode get_voicecase will handle the rest.
+ * when we are not in silence mode get_voicecase will handle the rest.
*/
-static int get_voice(jitterbuffer *jb, void **data, long now, long interpl)
+static int get_voice(jitterbuffer *jb, void **data, long now, long interpl)
{
- jb_frame *frame;
- long diff;
- int result;
-
- diff = jb->target - jb->current;
-
- //if the next frame is a silence frame, go in silence mode...
- if((get_next_frametype(jb, now - jb->current) == JB_TYPE_SILENCE) ) {
- jb_dbg("gs");
- frame = get_frame(jb, now - jb->current);
- *data = frame->data;
- frame->data = NULL;
- jb->info.silence =1;
- jb->silence_begin_ts = frame->ts;
- frame_free(frame);
- result = JB_OK;
- } else {
- if(jb->info.silence) { // we are in silence
- /*
- * During silence we can set the jitterbuffer size to the size
- * we want...
- */
- if (diff) {
- jb->current = jb->target;
- }
- frame = get_frame(jb, now - jb->current);
- if (frame) {
- if (jb->silence_begin_ts && frame->ts < jb->silence_begin_ts) {
- jb_dbg("gL");
- /* voice frame is late, next!*/
- jb->info.frames_late++;
- frame_free(frame);
- result = get_voice(jb, data, now, interpl);
- } else {
- jb_dbg("gP");
- /* voice frame */
- jb->info.silence = 0;
- jb->silence_begin_ts = 0;
- jb->next_voice_time = frame->ts + frame->ms;
- jb->info.last_voice_ms = frame->ms;
- *data = frame->data;
- frame->data = NULL;
- frame_free(frame);
- result = JB_OK;
+ jb_frame *frame;
+ long diff;
+ int result;
+
+ diff = jb->target - jb->current;
+
+ //if the next frame is a silence frame, go in silence mode...
+ if((get_next_frametype(jb, now - jb->current) == JB_TYPE_SILENCE) ) {
+ jb_dbg("gs");
+ frame = get_frame(jb, now - jb->current);
+ *data = frame->data;
+ frame->data = NULL;
+ jb->info.silence =1;
+ jb->silence_begin_ts = frame->ts;
+ frame_free(frame);
+ result = JB_OK;
+ }
+ else {
+ if(jb->info.silence) { // we are in silence
+ /*
+ * During silence we can set the jitterbuffer size to the size
+ * we want...
+ */
+ if (diff) {
+ jb->current = jb->target;
+ }
+ frame = get_frame(jb, now - jb->current);
+ if (frame) {
+ if (jb->silence_begin_ts && frame->ts < jb->silence_begin_ts) {
+ jb_dbg("gL");
+ /* voice frame is late, next!*/
+ jb->info.frames_late++;
+ frame_free(frame);
+ result = get_voice(jb, data, now, interpl);
+ }
+ else {
+ jb_dbg("gP");
+ /* voice frame */
+ jb->info.silence = 0;
+ jb->silence_begin_ts = 0;
+ jb->next_voice_time = frame->ts + frame->ms;
+ jb->info.last_voice_ms = frame->ms;
+ *data = frame->data;
+ frame->data = NULL;
+ frame_free(frame);
+ result = JB_OK;
+ }
+ }
+ else { //no frame
+ jb_dbg("gS");
+ result = JB_EMPTY;
+ }
+ }
+ else { //voice case
+ result = get_voicecase(jb,data,now,interpl,diff);
}
- } else { //no frame
- jb_dbg("gS");
- result = JB_EMPTY;
- }
- } else { //voice case
- result = get_voicecase(jb,data,now,interpl,diff);
- }
- }
- return result;
+ }
+ return result;
}
@@ -856,117 +880,125 @@ static int get_voice(jitterbuffer *jb, void **data, long now, long interpl)
* - diff < 0, we may need to shrink
* - everything else
*/
-static int get_voicecase(jitterbuffer *jb, void **data, long now, long interpl, long diff)
+static int get_voicecase(jitterbuffer *jb, void **data, long now, long interpl, long diff)
{
- jb_frame *frame;
- int result;
-
- // * - difference is way off, reset
- if (diff > jb->settings.max_diff || -diff > jb->settings.max_diff) {
- jb_err("wakko diff in get_voicecase\n");
- reset(jb); //reset hist because the timestamps are wakko.
- result = JB_NOFRAME;
- //- diff > 0, we may need to grow
- } else if ((diff > 0) &&
- (now > (jb->last_adjustment + jb->settings.wait_grow)
- || (now + jb->current + interpl) < get_next_framets(jb) ) ) { //grow
- /* first try to grow */
- if (diff<interpl/2) {
- jb_dbg("ag");
- jb->current +=diff;
- } else {
- jb_dbg("aG");
- /* grow by interp frame len */
- jb->current += interpl;
- }
- jb->last_adjustment = now;
- result = get_voice(jb, data, now, interpl);
- //- diff < 0, we may need to shrink
- } else if ( (diff < 0)
- && (now > (jb->last_adjustment + jb->settings.wait_shrink))
- && ((-diff) > jb->settings.extra_delay) ) {
- /* now try to shrink
- * if there is a frame shrink by frame length
- * otherwise shrink by interpl
- */
- jb->last_adjustment = now;
-
- frame = get_frame(jb, now - jb->current);
- if(frame) {
- jb_dbg("as");
- /* shrink by frame size we're throwing out */
- jb->info.frames_dropped++;
- jb->current -= frame->ms;
- frame_free(frame);
- } else {
- jb_dbg("aS");
- /* shrink by interpl */
- jb->current -= interpl;
- }
- result = get_voice(jb, data, now, interpl);
- } else {
- /* if it is not the time to play a result = JB_NOFRAME
- * else We try to play a frame if a frame is available
- * and not late it is played otherwise
- * if available it is dropped and the next is tried
- * last option is interpolating
- */
- if (now - jb->current < jb->next_voice_time) {
- jb_dbg("aN");
- result = JB_NOFRAME;
- } else {
- frame = get_frame(jb, now - jb->current);
- if (frame) { //there is a frame
- /* voice frame is late */
- if(frame->ts < jb->next_voice_time) { //late
- jb_dbg("aL");
- jb->info.frames_late++;
- frame_free(frame);
- result = get_voice(jb, data, now, interpl);
- } else {
- jb_dbg("aP");
- /* normal case; return the frame, increment stuff */
- *data = frame->data;
- frame->data = NULL;
- jb->next_voice_time = frame->ts + frame->ms;
- jb->cnt_successive_interp = 0;
- frame_free(frame);
- result = JB_OK;
+ jb_frame *frame;
+ int result;
+
+ // * - difference is way off, reset
+ if (diff > jb->settings.max_diff || -diff > jb->settings.max_diff) {
+ jb_err("wakko diff in get_voicecase\n");
+ reset(jb); //reset hist because the timestamps are wakko.
+ result = JB_NOFRAME;
+ //- diff > 0, we may need to grow
+ }
+ else if ((diff > 0) &&
+ (now > (jb->last_adjustment + jb->settings.wait_grow)
+ || (now + jb->current + interpl) < get_next_framets(jb) ) ) { //grow
+ /* first try to grow */
+ if (diff<interpl/2) {
+ jb_dbg("ag");
+ jb->current +=diff;
}
- } else { // no frame, thus interpolate
- jb->cnt_successive_interp++;
- /* assume silence instead of continuing to interpolate */
- if (jb->settings.max_successive_interp && jb->cnt_successive_interp >= jb->settings.max_successive_interp) {
- jb->info.silence = 1;
- jb->silence_begin_ts = jb->next_voice_time;
+ else {
+ jb_dbg("aG");
+ /* grow by interp frame len */
+ jb->current += interpl;
}
- jb_dbg("aI");
- jb->next_voice_time += interpl;
- result = JB_INTERP;
- }
+ jb->last_adjustment = now;
+ result = get_voice(jb, data, now, interpl);
+ //- diff < 0, we may need to shrink
}
- }
- return result;
+ else if ( (diff < 0)
+ && (now > (jb->last_adjustment + jb->settings.wait_shrink))
+ && ((-diff) > jb->settings.extra_delay) ) {
+ /* now try to shrink
+ * if there is a frame shrink by frame length
+ * otherwise shrink by interpl
+ */
+ jb->last_adjustment = now;
+
+ frame = get_frame(jb, now - jb->current);
+ if(frame) {
+ jb_dbg("as");
+ /* shrink by frame size we're throwing out */
+ jb->info.frames_dropped++;
+ jb->current -= frame->ms;
+ frame_free(frame);
+ }
+ else {
+ jb_dbg("aS");
+ /* shrink by interpl */
+ jb->current -= interpl;
+ }
+ result = get_voice(jb, data, now, interpl);
+ }
+ else {
+ /* if it is not the time to play a result = JB_NOFRAME
+ * else We try to play a frame if a frame is available
+ * and not late it is played otherwise
+ * if available it is dropped and the next is tried
+ * last option is interpolating
+ */
+ if (now - jb->current < jb->next_voice_time) {
+ jb_dbg("aN");
+ result = JB_NOFRAME;
+ }
+ else {
+ frame = get_frame(jb, now - jb->current);
+ if (frame) { //there is a frame
+ /* voice frame is late */
+ if(frame->ts < jb->next_voice_time) { //late
+ jb_dbg("aL");
+ jb->info.frames_late++;
+ frame_free(frame);
+ result = get_voice(jb, data, now, interpl);
+ }
+ else {
+ jb_dbg("aP");
+ /* normal case; return the frame, increment stuff */
+ *data = frame->data;
+ frame->data = NULL;
+ jb->next_voice_time = frame->ts + frame->ms;
+ jb->cnt_successive_interp = 0;
+ frame_free(frame);
+ result = JB_OK;
+ }
+ }
+ else { // no frame, thus interpolate
+ jb->cnt_successive_interp++;
+ /* assume silence instead of continuing to interpolate */
+ if (jb->settings.max_successive_interp && jb->cnt_successive_interp >= jb->settings.max_successive_interp) {
+ jb->info.silence = 1;
+ jb->silence_begin_ts = jb->next_voice_time;
+ }
+ jb_dbg("aI");
+ jb->next_voice_time += interpl;
+ result = JB_INTERP;
+ }
+ }
+ }
+ return result;
}
/***********
- * if there are frames and next frame->ts is smaller or equal ts
+ * if there are frames and next frame->ts is smaller or equal ts
* return type of next frame.
* else return 0
*/
-static int get_next_frametype(jitterbuffer *jb, long ts)
+static int get_next_frametype(jitterbuffer *jb, long ts)
{
- jb_frame *frame;
- int result;
-
- result = 0;
- frame = jb->voiceframes;
- if (frame && frame->ts <= ts) {
- result = frame->type;
- }
- return result;
+ jb_frame *frame;
+ int result;
+
+ result = 0;
+ frame = jb->voiceframes;
+ if (frame && frame->ts <= ts) {
+ result = frame->type;
+ }
+ return result;
}
@@ -974,62 +1006,64 @@ static int get_next_frametype(jitterbuffer *jb, long ts)
* returns ts from next frame in jb->voiceframes
* or returns LONG_MAX if there is no frame
*/
-static long get_next_framets(jitterbuffer *jb)
+static long get_next_framets(jitterbuffer *jb)
{
- if (jb->voiceframes) {
- return jb->voiceframes->ts;
- }
- return LONG_MAX;
+ if (jb->voiceframes) {
+ return jb->voiceframes->ts;
+ }
+ return LONG_MAX;
}
/***********
- * if there is a frame in jb->voiceframes and
+ * if there is a frame in jb->voiceframes and
* has a timestamp smaller/equal to ts
- * this frame will be returned and
+ * this frame will be returned and
* removed from the queue
*/
-static jb_frame *get_frame(jitterbuffer *jb, long ts)
+static jb_frame *get_frame(jitterbuffer *jb, long ts)
{
- jb_frame *frame;
-
- frame = jb->voiceframes;
- if (frame && frame->ts <= ts) {
- if(frame->next == frame) {
- jb->voiceframes = NULL;
- } else {
- /* remove this frame */
- frame->prev->next = frame->next;
- frame->next->prev = frame->prev;
- jb->voiceframes = frame->next;
- }
- return frame;
- }
- return NULL;
+ jb_frame *frame;
+
+ frame = jb->voiceframes;
+ if (frame && frame->ts <= ts) {
+ if(frame->next == frame) {
+ jb->voiceframes = NULL;
+ }
+ else {
+ /* remove this frame */
+ frame->prev->next = frame->next;
+ frame->next->prev = frame->prev;
+ jb->voiceframes = frame->next;
+ }
+ return frame;
+ }
+ return NULL;
}
/***********
* if there is a frame in jb->voiceframes
- * this frame will be unconditionally returned and
+ * this frame will be unconditionally returned and
* removed from the queue
*/
-static jb_frame *get_all_frames(jitterbuffer *jb)
+static jb_frame *get_all_frames(jitterbuffer *jb)
{
- jb_frame *frame;
-
- frame = jb->voiceframes;
- if (frame) {
- if(frame->next == frame) {
- jb->voiceframes = NULL;
- } else {
- /* remove this frame */
- frame->prev->next = frame->next;
- frame->next->prev = frame->prev;
- jb->voiceframes = frame->next;
- }
- return frame;
- }
- return NULL;
+ jb_frame *frame;
+
+ frame = jb->voiceframes;
+ if (frame) {
+ if(frame->next == frame) {
+ jb->voiceframes = NULL;
+ }
+ else {
+ /* remove this frame */
+ frame->prev->next = frame->next;
+ frame->next->prev = frame->prev;
+ jb->voiceframes = frame->next;
+ }
+ return frame;
+ }
+ return NULL;
}
OpenPOWER on IntegriCloud