doubango/tinyDAV/src/audio/tdav_jitterbuffer.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /* File from: http://cms.speakup.nl/tech/opensource/jitterbuffer/verslag-20051209.pdf/ */
 
 /*******************************************************
 * jitterbuffer:
 * an application-independent jitterbuffer, which tries
 * to achieve the maximum user perception during a call.
 * For more information look at:
 * http://www.speakup.nl/opensource/jitterbuffer/
 *
 * Copyright on this file is held by:
 * - Jesse Kaijen <jesse@speakup.nl>
 * - SpeakUp <info@speakup.nl>
 *
 * Contributors:
 * Jesse Kaijen <jesse@speakup.nl>
 *
 * This program is free software, distributed under the terms of:
 * - the GNU Lesser (Library) General Public License
 * - the Mozilla Public License
 *
 * if you are interested in an different licence type, please contact us.
 *
 * How to use the jitterbuffer, please look at the comments
 * in the headerfile.
 *
 * Further details on specific implementations,
 * please look at the comments in the code file.
 */
 #include "tinydav/audio/tdav_jitterbuffer.h"
 
 #if !(HAVE_SPEEX_DSP && HAVE_SPEEX_JB)
 
 #include "tsk_memory.h"
 
 #include <stdlib.h>
 #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_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
 
 //public functions
 jitterbuffer *jb_new();
 void jb_reset(jitterbuffer *jb);
 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); 
 int jb_has_frames(jitterbuffer *jb);
 
 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 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_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 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) {
     warnf = warn;
     errf = err;
     dbgf = dbg;
 }
 
 
 /***********
  * create a new jitterbuffer
  * return NULL if malloc doesn't work
  * else return jb with default_settings.
  */
 jitterbuffer *jb_new() 
 {
   jitterbuffer *jb;
   
   jb_dbg("N");
   #if HAVE_CRT //Debug memory
 		jb =calloc(1, sizeof(jitterbuffer));
 	#else
 		jb = tsk_calloc(1, sizeof(jitterbuffer));
 	#endif //HAVE_CRT
   
   if (!jb) {
     jb_err("cannot allocate jitterbuffer\n");
     return NULL;
   }
   set_default_settings(jb);
   reset(jb);
   return jb;
 }
 
 
 /***********
  * empty voice messages 
  * reset statistics 
  * keep the settings
  */
 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);
 }
 
 
 /***********
  * empty nonvoice messages
  * empty voice messages
  * reset statistics 
  * reset settings to default
  */
 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);
 }
 
 
 /***********
  * destroy the jitterbuffer
  * free all the [non]voice frames with reset_all
  * free the jitterbuffer
  */
 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);
 }
 
 
 /***********
  * 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) 
 {
   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;
   }
 }
 
 
 /***********
  * validates the statistics
  * the losspct due the jitterbuffer will be calculated.
  * delay and delay_target will be calculated
  * *stats = info
  */
 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;
 }
 
 
 /***********
  * gives the settings for this jitterbuffer
  * *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;
 }
 
 
 /***********
  * 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 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;
 
     case JB_CODEC_G711x:
       result = (4.42f - 0.63f*p - 0.0071f*d);
     break;
     
     case JB_CODEC_OTHER:
     default:
       result = (4.42f - 0.63f*p - 0.0071f*d);
 
   }
   return result;
 }
 
 
 /***********
  * if there are any frames left in JB returns JB_OK, otherwise returns JB_EMPTY
  */
 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;
   }
 }
 
 
 /***********
  * 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);
   }
 }
 
 
 /***********
  * control frames have a higher priority then voice frames
  * returns JB_OK if a frame is available and *data points to the packet
  * returns JB_NOFRAME if it's no time to play voice and no control available
  * 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 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 
  */
 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;
 }
 
 
 /***********
  * 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
 }
 
 
 /***********
  * Search algorithm
  * @REQUIRE max_index is within array
  *
  * Find the position of value in hist_sorted_delay
  * 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. 
  * 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) 
 {
   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) 
 {
   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) 
 {
   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 
  */
 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;
   }
 }
 
 
 /***********
  * 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 
  * - add new value to history & sorted_history_delay & sorted_history_timestamp
  * - 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) 
 {
   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++;
 }
 
 
 /***********
  * this tries to make a jitterbuffer that behaves like
  * the jitterbuffer proposed in this article:
  * 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) 
 {
   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) 
 {
   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;
 }
 
 
 /***********
  * returns JB_OK if a frame is available and *data points to the packet
  * 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. 
  */
 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;
         }
       } else {    //no frame 
         jb_dbg("gS");
         result = JB_EMPTY;
       }
     } else { //voice case
       result = get_voicecase(jb,data,now,interpl,diff);
     }
   }
   return result;
 }
 
 
 /***********
  * The voicecase has four 'options'
  * - difference is way off, reset
  * - diff > 0, we may need to grow
  * - diff < 0, we may need to shrink
  * - everything else
  */
 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;
         }
       } 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 
  *   return type of next frame.
  * else return 0
  */
 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;
 }
 
 
 /***********
  * returns ts from next frame in jb->voiceframes
  * or returns LONG_MAX if there is no frame
  */
 static long get_next_framets(jitterbuffer *jb) 
 {
   if (jb->voiceframes) {
     return jb->voiceframes->ts;
   }
   return LONG_MAX;
 }
 
 
 /***********
  * if there is a frame in jb->voiceframes and 
  * has a timestamp smaller/equal to ts
  * this frame will be returned and 
  * removed from the queue
  */
 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;
 }
 
 /***********
  * if there is a frame in jb->voiceframes
  * this frame will be unconditionally returned and 
  * removed from the queue
  */
 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;
 }
 
 
 #endif // !(HAVE_SPEEX_DSP && HAVE_SPEEX_JB)