xref: /aosp_15_r20/external/speex/libspeexdsp/jitter.c (revision 28e138c64d234588b5cd2a8a403b584bd3036e4e)
1*28e138c6SAndroid Build Coastguard Worker /* Copyright (C) 2002 Jean-Marc Valin
2*28e138c6SAndroid Build Coastguard Worker    File: speex_jitter.h
3*28e138c6SAndroid Build Coastguard Worker 
4*28e138c6SAndroid Build Coastguard Worker    Adaptive jitter buffer for Speex
5*28e138c6SAndroid Build Coastguard Worker 
6*28e138c6SAndroid Build Coastguard Worker    Redistribution and use in source and binary forms, with or without
7*28e138c6SAndroid Build Coastguard Worker    modification, are permitted provided that the following conditions
8*28e138c6SAndroid Build Coastguard Worker    are met:
9*28e138c6SAndroid Build Coastguard Worker 
10*28e138c6SAndroid Build Coastguard Worker    - Redistributions of source code must retain the above copyright
11*28e138c6SAndroid Build Coastguard Worker    notice, this list of conditions and the following disclaimer.
12*28e138c6SAndroid Build Coastguard Worker 
13*28e138c6SAndroid Build Coastguard Worker    - Redistributions in binary form must reproduce the above copyright
14*28e138c6SAndroid Build Coastguard Worker    notice, this list of conditions and the following disclaimer in the
15*28e138c6SAndroid Build Coastguard Worker    documentation and/or other materials provided with the distribution.
16*28e138c6SAndroid Build Coastguard Worker 
17*28e138c6SAndroid Build Coastguard Worker    - Neither the name of the Xiph.org Foundation nor the names of its
18*28e138c6SAndroid Build Coastguard Worker    contributors may be used to endorse or promote products derived from
19*28e138c6SAndroid Build Coastguard Worker    this software without specific prior written permission.
20*28e138c6SAndroid Build Coastguard Worker 
21*28e138c6SAndroid Build Coastguard Worker    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*28e138c6SAndroid Build Coastguard Worker    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*28e138c6SAndroid Build Coastguard Worker    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24*28e138c6SAndroid Build Coastguard Worker    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
25*28e138c6SAndroid Build Coastguard Worker    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26*28e138c6SAndroid Build Coastguard Worker    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27*28e138c6SAndroid Build Coastguard Worker    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28*28e138c6SAndroid Build Coastguard Worker    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29*28e138c6SAndroid Build Coastguard Worker    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30*28e138c6SAndroid Build Coastguard Worker    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31*28e138c6SAndroid Build Coastguard Worker    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*28e138c6SAndroid Build Coastguard Worker 
33*28e138c6SAndroid Build Coastguard Worker */
34*28e138c6SAndroid Build Coastguard Worker 
35*28e138c6SAndroid Build Coastguard Worker /*
36*28e138c6SAndroid Build Coastguard Worker TODO:
37*28e138c6SAndroid Build Coastguard Worker - Add short-term estimate
38*28e138c6SAndroid Build Coastguard Worker - Defensive programming
39*28e138c6SAndroid Build Coastguard Worker   + warn when last returned < last desired (begative buffering)
40*28e138c6SAndroid Build Coastguard Worker   + warn if update_delay not called between get() and tick() or is called twice in a row
41*28e138c6SAndroid Build Coastguard Worker - Linked list structure for holding the packets instead of the current fixed-size array
42*28e138c6SAndroid Build Coastguard Worker   + return memory to a pool
43*28e138c6SAndroid Build Coastguard Worker   + allow pre-allocation of the pool
44*28e138c6SAndroid Build Coastguard Worker   + optional max number of elements
45*28e138c6SAndroid Build Coastguard Worker - Statistics
46*28e138c6SAndroid Build Coastguard Worker   + drift
47*28e138c6SAndroid Build Coastguard Worker   + loss
48*28e138c6SAndroid Build Coastguard Worker   + late
49*28e138c6SAndroid Build Coastguard Worker   + jitter
50*28e138c6SAndroid Build Coastguard Worker   + buffering delay
51*28e138c6SAndroid Build Coastguard Worker */
52*28e138c6SAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
53*28e138c6SAndroid Build Coastguard Worker #include "config.h"
54*28e138c6SAndroid Build Coastguard Worker #endif
55*28e138c6SAndroid Build Coastguard Worker 
56*28e138c6SAndroid Build Coastguard Worker 
57*28e138c6SAndroid Build Coastguard Worker #include "arch.h"
58*28e138c6SAndroid Build Coastguard Worker #include "speex/speex_jitter.h"
59*28e138c6SAndroid Build Coastguard Worker #include "os_support.h"
60*28e138c6SAndroid Build Coastguard Worker 
61*28e138c6SAndroid Build Coastguard Worker #ifndef NULL
62*28e138c6SAndroid Build Coastguard Worker #define NULL 0
63*28e138c6SAndroid Build Coastguard Worker #endif
64*28e138c6SAndroid Build Coastguard Worker 
65*28e138c6SAndroid Build Coastguard Worker #define SPEEX_JITTER_MAX_BUFFER_SIZE 200   /**< Maximum number of packets in jitter buffer */
66*28e138c6SAndroid Build Coastguard Worker 
67*28e138c6SAndroid Build Coastguard Worker #define TSUB(a,b) ((spx_int32_t)((a)-(b)))
68*28e138c6SAndroid Build Coastguard Worker 
69*28e138c6SAndroid Build Coastguard Worker #define GT32(a,b) (((spx_int32_t)((a)-(b)))>0)
70*28e138c6SAndroid Build Coastguard Worker #define GE32(a,b) (((spx_int32_t)((a)-(b)))>=0)
71*28e138c6SAndroid Build Coastguard Worker #define LT32(a,b) (((spx_int32_t)((a)-(b)))<0)
72*28e138c6SAndroid Build Coastguard Worker #define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0)
73*28e138c6SAndroid Build Coastguard Worker 
74*28e138c6SAndroid Build Coastguard Worker #define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step))
75*28e138c6SAndroid Build Coastguard Worker 
76*28e138c6SAndroid Build Coastguard Worker #define MAX_TIMINGS 40
77*28e138c6SAndroid Build Coastguard Worker #define MAX_BUFFERS 3
78*28e138c6SAndroid Build Coastguard Worker #define TOP_DELAY 40
79*28e138c6SAndroid Build Coastguard Worker 
80*28e138c6SAndroid Build Coastguard Worker /** Buffer that keeps the time of arrival of the latest packets */
81*28e138c6SAndroid Build Coastguard Worker struct TimingBuffer {
82*28e138c6SAndroid Build Coastguard Worker    int filled;                         /**< Number of entries occupied in "timing" and "counts"*/
83*28e138c6SAndroid Build Coastguard Worker    int curr_count;                     /**< Number of packet timings we got (including those we discarded) */
84*28e138c6SAndroid Build Coastguard Worker    spx_int32_t timing[MAX_TIMINGS];    /**< Sorted list of all timings ("latest" packets first) */
85*28e138c6SAndroid Build Coastguard Worker    spx_int16_t counts[MAX_TIMINGS];    /**< Order the packets were put in (will be used for short-term estimate) */
86*28e138c6SAndroid Build Coastguard Worker };
87*28e138c6SAndroid Build Coastguard Worker 
tb_init(struct TimingBuffer * tb)88*28e138c6SAndroid Build Coastguard Worker static void tb_init(struct TimingBuffer *tb)
89*28e138c6SAndroid Build Coastguard Worker {
90*28e138c6SAndroid Build Coastguard Worker    tb->filled = 0;
91*28e138c6SAndroid Build Coastguard Worker    tb->curr_count = 0;
92*28e138c6SAndroid Build Coastguard Worker }
93*28e138c6SAndroid Build Coastguard Worker 
94*28e138c6SAndroid Build Coastguard Worker /* Add the timing of a new packet to the TimingBuffer */
tb_add(struct TimingBuffer * tb,spx_int16_t timing)95*28e138c6SAndroid Build Coastguard Worker static void tb_add(struct TimingBuffer *tb, spx_int16_t timing)
96*28e138c6SAndroid Build Coastguard Worker {
97*28e138c6SAndroid Build Coastguard Worker    int pos;
98*28e138c6SAndroid Build Coastguard Worker    /* Discard packet that won't make it into the list because they're too early */
99*28e138c6SAndroid Build Coastguard Worker    if (tb->filled >= MAX_TIMINGS && timing >= tb->timing[tb->filled-1])
100*28e138c6SAndroid Build Coastguard Worker    {
101*28e138c6SAndroid Build Coastguard Worker       tb->curr_count++;
102*28e138c6SAndroid Build Coastguard Worker       return;
103*28e138c6SAndroid Build Coastguard Worker    }
104*28e138c6SAndroid Build Coastguard Worker 
105*28e138c6SAndroid Build Coastguard Worker    /* Find where the timing info goes in the sorted list */
106*28e138c6SAndroid Build Coastguard Worker    pos = 0;
107*28e138c6SAndroid Build Coastguard Worker    /* FIXME: Do bisection instead of linear search */
108*28e138c6SAndroid Build Coastguard Worker    while (pos<tb->filled && timing >= tb->timing[pos])
109*28e138c6SAndroid Build Coastguard Worker    {
110*28e138c6SAndroid Build Coastguard Worker       pos++;
111*28e138c6SAndroid Build Coastguard Worker    }
112*28e138c6SAndroid Build Coastguard Worker 
113*28e138c6SAndroid Build Coastguard Worker    speex_assert(pos <= tb->filled && pos < MAX_TIMINGS);
114*28e138c6SAndroid Build Coastguard Worker 
115*28e138c6SAndroid Build Coastguard Worker    /* Shift everything so we can perform the insertion */
116*28e138c6SAndroid Build Coastguard Worker    if (pos < tb->filled)
117*28e138c6SAndroid Build Coastguard Worker    {
118*28e138c6SAndroid Build Coastguard Worker       int move_size = tb->filled-pos;
119*28e138c6SAndroid Build Coastguard Worker       if (tb->filled == MAX_TIMINGS)
120*28e138c6SAndroid Build Coastguard Worker          move_size -= 1;
121*28e138c6SAndroid Build Coastguard Worker       SPEEX_MOVE(&tb->timing[pos+1], &tb->timing[pos], move_size);
122*28e138c6SAndroid Build Coastguard Worker       SPEEX_MOVE(&tb->counts[pos+1], &tb->counts[pos], move_size);
123*28e138c6SAndroid Build Coastguard Worker    }
124*28e138c6SAndroid Build Coastguard Worker    /* Insert */
125*28e138c6SAndroid Build Coastguard Worker    tb->timing[pos] = timing;
126*28e138c6SAndroid Build Coastguard Worker    tb->counts[pos] = tb->curr_count;
127*28e138c6SAndroid Build Coastguard Worker 
128*28e138c6SAndroid Build Coastguard Worker    tb->curr_count++;
129*28e138c6SAndroid Build Coastguard Worker    if (tb->filled<MAX_TIMINGS)
130*28e138c6SAndroid Build Coastguard Worker       tb->filled++;
131*28e138c6SAndroid Build Coastguard Worker }
132*28e138c6SAndroid Build Coastguard Worker 
133*28e138c6SAndroid Build Coastguard Worker 
134*28e138c6SAndroid Build Coastguard Worker 
135*28e138c6SAndroid Build Coastguard Worker /** Jitter buffer structure */
136*28e138c6SAndroid Build Coastguard Worker struct JitterBuffer_ {
137*28e138c6SAndroid Build Coastguard Worker    spx_uint32_t pointer_timestamp;                             /**< Timestamp of what we will *get* next */
138*28e138c6SAndroid Build Coastguard Worker    spx_uint32_t last_returned_timestamp;                       /**< Useful for getting the next packet with the same timestamp (for fragmented media) */
139*28e138c6SAndroid Build Coastguard Worker    spx_uint32_t next_stop;                                     /**< Estimated time the next get() will be called */
140*28e138c6SAndroid Build Coastguard Worker 
141*28e138c6SAndroid Build Coastguard Worker    spx_int32_t buffered;                                       /**< Amount of data we think is still buffered by the application (timestamp units)*/
142*28e138c6SAndroid Build Coastguard Worker 
143*28e138c6SAndroid Build Coastguard Worker    JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE];   /**< Packets stored in the buffer */
144*28e138c6SAndroid Build Coastguard Worker    spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE];         /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */
145*28e138c6SAndroid Build Coastguard Worker 
146*28e138c6SAndroid Build Coastguard Worker    void (*destroy) (void *);                                   /**< Callback for destroying a packet */
147*28e138c6SAndroid Build Coastguard Worker 
148*28e138c6SAndroid Build Coastguard Worker    spx_int32_t delay_step;                                     /**< Size of the steps when adjusting buffering (timestamp units) */
149*28e138c6SAndroid Build Coastguard Worker    spx_int32_t concealment_size;                               /**< Size of the packet loss concealment "units" */
150*28e138c6SAndroid Build Coastguard Worker    int reset_state;                                            /**< True if state was just reset        */
151*28e138c6SAndroid Build Coastguard Worker    int buffer_margin;                                          /**< How many frames we want to keep in the buffer (lower bound) */
152*28e138c6SAndroid Build Coastguard Worker    int late_cutoff;                                            /**< How late must a packet be for it not to be considered at all */
153*28e138c6SAndroid Build Coastguard Worker    int interp_requested;                                       /**< An interpolation is requested by speex_jitter_update_delay() */
154*28e138c6SAndroid Build Coastguard Worker    int auto_adjust;                                            /**< Whether to automatically adjust the delay at any time */
155*28e138c6SAndroid Build Coastguard Worker 
156*28e138c6SAndroid Build Coastguard Worker    struct TimingBuffer _tb[MAX_BUFFERS];                       /**< Don't use those directly */
157*28e138c6SAndroid Build Coastguard Worker    struct TimingBuffer *timeBuffers[MAX_BUFFERS];              /**< Storing arrival time of latest frames so we can compute some stats */
158*28e138c6SAndroid Build Coastguard Worker    int window_size;                                            /**< Total window over which the late frames are counted */
159*28e138c6SAndroid Build Coastguard Worker    int subwindow_size;                                         /**< Sub-window size for faster computation  */
160*28e138c6SAndroid Build Coastguard Worker    int max_late_rate;                                          /**< Absolute maximum amount of late packets tolerable (in percent) */
161*28e138c6SAndroid Build Coastguard Worker    int latency_tradeoff;                                       /**< Latency equivalent of losing one percent of packets */
162*28e138c6SAndroid Build Coastguard Worker    int auto_tradeoff;                                          /**< Latency equivalent of losing one percent of packets (automatic default) */
163*28e138c6SAndroid Build Coastguard Worker 
164*28e138c6SAndroid Build Coastguard Worker    int lost_count;                                             /**< Number of consecutive lost packets  */
165*28e138c6SAndroid Build Coastguard Worker };
166*28e138c6SAndroid Build Coastguard Worker 
167*28e138c6SAndroid Build Coastguard Worker /** Based on available data, this computes the optimal delay for the jitter buffer.
168*28e138c6SAndroid Build Coastguard Worker    The optimised function is in timestamp units and is:
169*28e138c6SAndroid Build Coastguard Worker    cost = delay + late_factor*[number of frames that would be late if we used that delay]
170*28e138c6SAndroid Build Coastguard Worker    @param tb Array of buffers
171*28e138c6SAndroid Build Coastguard Worker    @param late_factor Equivalent cost of a late frame (in timestamp units)
172*28e138c6SAndroid Build Coastguard Worker  */
compute_opt_delay(JitterBuffer * jitter)173*28e138c6SAndroid Build Coastguard Worker static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
174*28e138c6SAndroid Build Coastguard Worker {
175*28e138c6SAndroid Build Coastguard Worker    int i;
176*28e138c6SAndroid Build Coastguard Worker    spx_int16_t opt=0;
177*28e138c6SAndroid Build Coastguard Worker    spx_int32_t best_cost=0x7fffffff;
178*28e138c6SAndroid Build Coastguard Worker    int late = 0;
179*28e138c6SAndroid Build Coastguard Worker    int pos[MAX_BUFFERS];
180*28e138c6SAndroid Build Coastguard Worker    int tot_count;
181*28e138c6SAndroid Build Coastguard Worker    float late_factor;
182*28e138c6SAndroid Build Coastguard Worker    int penalty_taken = 0;
183*28e138c6SAndroid Build Coastguard Worker    int best = 0;
184*28e138c6SAndroid Build Coastguard Worker    int worst = 0;
185*28e138c6SAndroid Build Coastguard Worker    spx_int32_t deltaT;
186*28e138c6SAndroid Build Coastguard Worker    struct TimingBuffer *tb;
187*28e138c6SAndroid Build Coastguard Worker 
188*28e138c6SAndroid Build Coastguard Worker    tb = jitter->_tb;
189*28e138c6SAndroid Build Coastguard Worker 
190*28e138c6SAndroid Build Coastguard Worker    /* Number of packet timings we have received (including those we didn't keep) */
191*28e138c6SAndroid Build Coastguard Worker    tot_count = 0;
192*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<MAX_BUFFERS;i++)
193*28e138c6SAndroid Build Coastguard Worker       tot_count += tb[i].curr_count;
194*28e138c6SAndroid Build Coastguard Worker    if (tot_count==0)
195*28e138c6SAndroid Build Coastguard Worker       return 0;
196*28e138c6SAndroid Build Coastguard Worker 
197*28e138c6SAndroid Build Coastguard Worker    /* Compute cost for one lost packet */
198*28e138c6SAndroid Build Coastguard Worker    if (jitter->latency_tradeoff != 0)
199*28e138c6SAndroid Build Coastguard Worker       late_factor = jitter->latency_tradeoff * 100.0f / tot_count;
200*28e138c6SAndroid Build Coastguard Worker    else
201*28e138c6SAndroid Build Coastguard Worker       late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count;
202*28e138c6SAndroid Build Coastguard Worker 
203*28e138c6SAndroid Build Coastguard Worker    /*fprintf(stderr, "late_factor = %f\n", late_factor);*/
204*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<MAX_BUFFERS;i++)
205*28e138c6SAndroid Build Coastguard Worker       pos[i] = 0;
206*28e138c6SAndroid Build Coastguard Worker 
207*28e138c6SAndroid Build Coastguard Worker    /* Pick the TOP_DELAY "latest" packets (doesn't need to actually be late
208*28e138c6SAndroid Build Coastguard Worker       for the current settings) */
209*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<TOP_DELAY;i++)
210*28e138c6SAndroid Build Coastguard Worker    {
211*28e138c6SAndroid Build Coastguard Worker       int j;
212*28e138c6SAndroid Build Coastguard Worker       int next=-1;
213*28e138c6SAndroid Build Coastguard Worker       int latest = 32767;
214*28e138c6SAndroid Build Coastguard Worker       /* Pick latest amoung all sub-windows */
215*28e138c6SAndroid Build Coastguard Worker       for (j=0;j<MAX_BUFFERS;j++)
216*28e138c6SAndroid Build Coastguard Worker       {
217*28e138c6SAndroid Build Coastguard Worker          if (pos[j] < tb[j].filled && tb[j].timing[pos[j]] < latest)
218*28e138c6SAndroid Build Coastguard Worker          {
219*28e138c6SAndroid Build Coastguard Worker             next = j;
220*28e138c6SAndroid Build Coastguard Worker             latest = tb[j].timing[pos[j]];
221*28e138c6SAndroid Build Coastguard Worker          }
222*28e138c6SAndroid Build Coastguard Worker       }
223*28e138c6SAndroid Build Coastguard Worker       if (next != -1)
224*28e138c6SAndroid Build Coastguard Worker       {
225*28e138c6SAndroid Build Coastguard Worker          spx_int32_t cost;
226*28e138c6SAndroid Build Coastguard Worker 
227*28e138c6SAndroid Build Coastguard Worker          if (i==0)
228*28e138c6SAndroid Build Coastguard Worker             worst = latest;
229*28e138c6SAndroid Build Coastguard Worker          best = latest;
230*28e138c6SAndroid Build Coastguard Worker          latest = ROUND_DOWN(latest, jitter->delay_step);
231*28e138c6SAndroid Build Coastguard Worker          pos[next]++;
232*28e138c6SAndroid Build Coastguard Worker 
233*28e138c6SAndroid Build Coastguard Worker          /* Actual cost function that tells us how bad using this delay would be */
234*28e138c6SAndroid Build Coastguard Worker          cost = -latest + late_factor*late;
235*28e138c6SAndroid Build Coastguard Worker          /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/
236*28e138c6SAndroid Build Coastguard Worker          if (cost < best_cost)
237*28e138c6SAndroid Build Coastguard Worker          {
238*28e138c6SAndroid Build Coastguard Worker             best_cost = cost;
239*28e138c6SAndroid Build Coastguard Worker             opt = latest;
240*28e138c6SAndroid Build Coastguard Worker          }
241*28e138c6SAndroid Build Coastguard Worker       } else {
242*28e138c6SAndroid Build Coastguard Worker          break;
243*28e138c6SAndroid Build Coastguard Worker       }
244*28e138c6SAndroid Build Coastguard Worker 
245*28e138c6SAndroid Build Coastguard Worker       /* For the next timing we will consider, there will be one more late packet to count */
246*28e138c6SAndroid Build Coastguard Worker       late++;
247*28e138c6SAndroid Build Coastguard Worker       /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */
248*28e138c6SAndroid Build Coastguard Worker       if (latest >= 0 && !penalty_taken)
249*28e138c6SAndroid Build Coastguard Worker       {
250*28e138c6SAndroid Build Coastguard Worker          penalty_taken = 1;
251*28e138c6SAndroid Build Coastguard Worker          late+=4;
252*28e138c6SAndroid Build Coastguard Worker       }
253*28e138c6SAndroid Build Coastguard Worker    }
254*28e138c6SAndroid Build Coastguard Worker 
255*28e138c6SAndroid Build Coastguard Worker    deltaT = best-worst;
256*28e138c6SAndroid Build Coastguard Worker    /* This is a default "automatic latency tradeoff" when none is provided */
257*28e138c6SAndroid Build Coastguard Worker    jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY;
258*28e138c6SAndroid Build Coastguard Worker    /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/
259*28e138c6SAndroid Build Coastguard Worker 
260*28e138c6SAndroid Build Coastguard Worker    /* FIXME: Compute a short-term estimate too and combine with the long-term one */
261*28e138c6SAndroid Build Coastguard Worker 
262*28e138c6SAndroid Build Coastguard Worker    /* Prevents reducing the buffer size when we haven't really had much data */
263*28e138c6SAndroid Build Coastguard Worker    if (tot_count < TOP_DELAY && opt > 0)
264*28e138c6SAndroid Build Coastguard Worker       return 0;
265*28e138c6SAndroid Build Coastguard Worker    return opt;
266*28e138c6SAndroid Build Coastguard Worker }
267*28e138c6SAndroid Build Coastguard Worker 
268*28e138c6SAndroid Build Coastguard Worker 
269*28e138c6SAndroid Build Coastguard Worker /** Initialise jitter buffer */
jitter_buffer_init(int step_size)270*28e138c6SAndroid Build Coastguard Worker EXPORT JitterBuffer *jitter_buffer_init(int step_size)
271*28e138c6SAndroid Build Coastguard Worker {
272*28e138c6SAndroid Build Coastguard Worker    JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer));
273*28e138c6SAndroid Build Coastguard Worker    if (jitter)
274*28e138c6SAndroid Build Coastguard Worker    {
275*28e138c6SAndroid Build Coastguard Worker       int i;
276*28e138c6SAndroid Build Coastguard Worker       spx_int32_t tmp;
277*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
278*28e138c6SAndroid Build Coastguard Worker          jitter->packets[i].data=NULL;
279*28e138c6SAndroid Build Coastguard Worker       jitter->delay_step = step_size;
280*28e138c6SAndroid Build Coastguard Worker       jitter->concealment_size = step_size;
281*28e138c6SAndroid Build Coastguard Worker       /*FIXME: Should this be 0 or 1?*/
282*28e138c6SAndroid Build Coastguard Worker       jitter->buffer_margin = 0;
283*28e138c6SAndroid Build Coastguard Worker       jitter->late_cutoff = 50;
284*28e138c6SAndroid Build Coastguard Worker       jitter->destroy = NULL;
285*28e138c6SAndroid Build Coastguard Worker       jitter->latency_tradeoff = 0;
286*28e138c6SAndroid Build Coastguard Worker       jitter->auto_adjust = 1;
287*28e138c6SAndroid Build Coastguard Worker       tmp = 4;
288*28e138c6SAndroid Build Coastguard Worker       jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MAX_LATE_RATE, &tmp);
289*28e138c6SAndroid Build Coastguard Worker       jitter_buffer_reset(jitter);
290*28e138c6SAndroid Build Coastguard Worker    }
291*28e138c6SAndroid Build Coastguard Worker    return jitter;
292*28e138c6SAndroid Build Coastguard Worker }
293*28e138c6SAndroid Build Coastguard Worker 
294*28e138c6SAndroid Build Coastguard Worker /** Reset jitter buffer */
jitter_buffer_reset(JitterBuffer * jitter)295*28e138c6SAndroid Build Coastguard Worker EXPORT void jitter_buffer_reset(JitterBuffer *jitter)
296*28e138c6SAndroid Build Coastguard Worker {
297*28e138c6SAndroid Build Coastguard Worker    int i;
298*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
299*28e138c6SAndroid Build Coastguard Worker    {
300*28e138c6SAndroid Build Coastguard Worker       if (jitter->packets[i].data)
301*28e138c6SAndroid Build Coastguard Worker       {
302*28e138c6SAndroid Build Coastguard Worker          if (jitter->destroy)
303*28e138c6SAndroid Build Coastguard Worker             jitter->destroy(jitter->packets[i].data);
304*28e138c6SAndroid Build Coastguard Worker          else
305*28e138c6SAndroid Build Coastguard Worker             speex_free(jitter->packets[i].data);
306*28e138c6SAndroid Build Coastguard Worker          jitter->packets[i].data = NULL;
307*28e138c6SAndroid Build Coastguard Worker       }
308*28e138c6SAndroid Build Coastguard Worker    }
309*28e138c6SAndroid Build Coastguard Worker    /* Timestamp is actually undefined at this point */
310*28e138c6SAndroid Build Coastguard Worker    jitter->pointer_timestamp = 0;
311*28e138c6SAndroid Build Coastguard Worker    jitter->next_stop = 0;
312*28e138c6SAndroid Build Coastguard Worker    jitter->reset_state = 1;
313*28e138c6SAndroid Build Coastguard Worker    jitter->lost_count = 0;
314*28e138c6SAndroid Build Coastguard Worker    jitter->buffered = 0;
315*28e138c6SAndroid Build Coastguard Worker    jitter->auto_tradeoff = 32000;
316*28e138c6SAndroid Build Coastguard Worker 
317*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<MAX_BUFFERS;i++)
318*28e138c6SAndroid Build Coastguard Worker    {
319*28e138c6SAndroid Build Coastguard Worker       tb_init(&jitter->_tb[i]);
320*28e138c6SAndroid Build Coastguard Worker       jitter->timeBuffers[i] = &jitter->_tb[i];
321*28e138c6SAndroid Build Coastguard Worker    }
322*28e138c6SAndroid Build Coastguard Worker    /*fprintf (stderr, "reset\n");*/
323*28e138c6SAndroid Build Coastguard Worker }
324*28e138c6SAndroid Build Coastguard Worker 
325*28e138c6SAndroid Build Coastguard Worker /** Destroy jitter buffer */
jitter_buffer_destroy(JitterBuffer * jitter)326*28e138c6SAndroid Build Coastguard Worker EXPORT void jitter_buffer_destroy(JitterBuffer *jitter)
327*28e138c6SAndroid Build Coastguard Worker {
328*28e138c6SAndroid Build Coastguard Worker    jitter_buffer_reset(jitter);
329*28e138c6SAndroid Build Coastguard Worker    speex_free(jitter);
330*28e138c6SAndroid Build Coastguard Worker }
331*28e138c6SAndroid Build Coastguard Worker 
332*28e138c6SAndroid Build Coastguard Worker /** Take the following timing into consideration for future calculations */
update_timings(JitterBuffer * jitter,spx_int32_t timing)333*28e138c6SAndroid Build Coastguard Worker static void update_timings(JitterBuffer *jitter, spx_int32_t timing)
334*28e138c6SAndroid Build Coastguard Worker {
335*28e138c6SAndroid Build Coastguard Worker    if (timing < -32767)
336*28e138c6SAndroid Build Coastguard Worker       timing = -32767;
337*28e138c6SAndroid Build Coastguard Worker    if (timing > 32767)
338*28e138c6SAndroid Build Coastguard Worker       timing = 32767;
339*28e138c6SAndroid Build Coastguard Worker    /* If the current sub-window is full, perform a rotation and discard oldest sub-widow */
340*28e138c6SAndroid Build Coastguard Worker    if (jitter->timeBuffers[0]->curr_count >= jitter->subwindow_size)
341*28e138c6SAndroid Build Coastguard Worker    {
342*28e138c6SAndroid Build Coastguard Worker       int i;
343*28e138c6SAndroid Build Coastguard Worker       /*fprintf(stderr, "Rotate buffer\n");*/
344*28e138c6SAndroid Build Coastguard Worker       struct TimingBuffer *tmp = jitter->timeBuffers[MAX_BUFFERS-1];
345*28e138c6SAndroid Build Coastguard Worker       for (i=MAX_BUFFERS-1;i>=1;i--)
346*28e138c6SAndroid Build Coastguard Worker          jitter->timeBuffers[i] = jitter->timeBuffers[i-1];
347*28e138c6SAndroid Build Coastguard Worker       jitter->timeBuffers[0] = tmp;
348*28e138c6SAndroid Build Coastguard Worker       tb_init(jitter->timeBuffers[0]);
349*28e138c6SAndroid Build Coastguard Worker    }
350*28e138c6SAndroid Build Coastguard Worker    tb_add(jitter->timeBuffers[0], timing);
351*28e138c6SAndroid Build Coastguard Worker }
352*28e138c6SAndroid Build Coastguard Worker 
353*28e138c6SAndroid Build Coastguard Worker /** Compensate all timings when we do an adjustment of the buffering */
shift_timings(JitterBuffer * jitter,spx_int16_t amount)354*28e138c6SAndroid Build Coastguard Worker static void shift_timings(JitterBuffer *jitter, spx_int16_t amount)
355*28e138c6SAndroid Build Coastguard Worker {
356*28e138c6SAndroid Build Coastguard Worker    int i, j;
357*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<MAX_BUFFERS;i++)
358*28e138c6SAndroid Build Coastguard Worker    {
359*28e138c6SAndroid Build Coastguard Worker       for (j=0;j<jitter->timeBuffers[i]->filled;j++)
360*28e138c6SAndroid Build Coastguard Worker          jitter->timeBuffers[i]->timing[j] += amount;
361*28e138c6SAndroid Build Coastguard Worker    }
362*28e138c6SAndroid Build Coastguard Worker }
363*28e138c6SAndroid Build Coastguard Worker 
364*28e138c6SAndroid Build Coastguard Worker 
365*28e138c6SAndroid Build Coastguard Worker /** Put one packet into the jitter buffer */
jitter_buffer_put(JitterBuffer * jitter,const JitterBufferPacket * packet)366*28e138c6SAndroid Build Coastguard Worker EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
367*28e138c6SAndroid Build Coastguard Worker {
368*28e138c6SAndroid Build Coastguard Worker    int i,j;
369*28e138c6SAndroid Build Coastguard Worker    int late;
370*28e138c6SAndroid Build Coastguard Worker    /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
371*28e138c6SAndroid Build Coastguard Worker 
372*28e138c6SAndroid Build Coastguard Worker    /* Cleanup buffer (remove old packets that weren't played) */
373*28e138c6SAndroid Build Coastguard Worker    if (!jitter->reset_state)
374*28e138c6SAndroid Build Coastguard Worker    {
375*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
376*28e138c6SAndroid Build Coastguard Worker       {
377*28e138c6SAndroid Build Coastguard Worker          /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */
378*28e138c6SAndroid Build Coastguard Worker          if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp + jitter->packets[i].span, jitter->pointer_timestamp))
379*28e138c6SAndroid Build Coastguard Worker          {
380*28e138c6SAndroid Build Coastguard Worker             /*fprintf (stderr, "cleaned (not played)\n");*/
381*28e138c6SAndroid Build Coastguard Worker             if (jitter->destroy)
382*28e138c6SAndroid Build Coastguard Worker                jitter->destroy(jitter->packets[i].data);
383*28e138c6SAndroid Build Coastguard Worker             else
384*28e138c6SAndroid Build Coastguard Worker                speex_free(jitter->packets[i].data);
385*28e138c6SAndroid Build Coastguard Worker             jitter->packets[i].data = NULL;
386*28e138c6SAndroid Build Coastguard Worker          }
387*28e138c6SAndroid Build Coastguard Worker       }
388*28e138c6SAndroid Build Coastguard Worker    }
389*28e138c6SAndroid Build Coastguard Worker 
390*28e138c6SAndroid Build Coastguard Worker    /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/
391*28e138c6SAndroid Build Coastguard Worker    /* Check if packet is late (could still be useful though) */
392*28e138c6SAndroid Build Coastguard Worker    if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop))
393*28e138c6SAndroid Build Coastguard Worker    {
394*28e138c6SAndroid Build Coastguard Worker       update_timings(jitter, ((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->next_stop) - jitter->buffer_margin);
395*28e138c6SAndroid Build Coastguard Worker       late = 1;
396*28e138c6SAndroid Build Coastguard Worker    } else {
397*28e138c6SAndroid Build Coastguard Worker       late = 0;
398*28e138c6SAndroid Build Coastguard Worker    }
399*28e138c6SAndroid Build Coastguard Worker 
400*28e138c6SAndroid Build Coastguard Worker    /* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is
401*28e138c6SAndroid Build Coastguard Worker     * used to resync. */
402*28e138c6SAndroid Build Coastguard Worker    if (jitter->lost_count>20)
403*28e138c6SAndroid Build Coastguard Worker    {
404*28e138c6SAndroid Build Coastguard Worker       jitter_buffer_reset(jitter);
405*28e138c6SAndroid Build Coastguard Worker    }
406*28e138c6SAndroid Build Coastguard Worker 
407*28e138c6SAndroid Build Coastguard Worker    /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */
408*28e138c6SAndroid Build Coastguard Worker    if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp))
409*28e138c6SAndroid Build Coastguard Worker    {
410*28e138c6SAndroid Build Coastguard Worker 
411*28e138c6SAndroid Build Coastguard Worker       /*Find an empty slot in the buffer*/
412*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
413*28e138c6SAndroid Build Coastguard Worker       {
414*28e138c6SAndroid Build Coastguard Worker          if (jitter->packets[i].data==NULL)
415*28e138c6SAndroid Build Coastguard Worker             break;
416*28e138c6SAndroid Build Coastguard Worker       }
417*28e138c6SAndroid Build Coastguard Worker 
418*28e138c6SAndroid Build Coastguard Worker       /*No place left in the buffer, need to make room for it by discarding the oldest packet */
419*28e138c6SAndroid Build Coastguard Worker       if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
420*28e138c6SAndroid Build Coastguard Worker       {
421*28e138c6SAndroid Build Coastguard Worker          int earliest=jitter->packets[0].timestamp;
422*28e138c6SAndroid Build Coastguard Worker          i=0;
423*28e138c6SAndroid Build Coastguard Worker          for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
424*28e138c6SAndroid Build Coastguard Worker          {
425*28e138c6SAndroid Build Coastguard Worker             if (!jitter->packets[i].data || LT32(jitter->packets[j].timestamp,earliest))
426*28e138c6SAndroid Build Coastguard Worker             {
427*28e138c6SAndroid Build Coastguard Worker                earliest = jitter->packets[j].timestamp;
428*28e138c6SAndroid Build Coastguard Worker                i=j;
429*28e138c6SAndroid Build Coastguard Worker             }
430*28e138c6SAndroid Build Coastguard Worker          }
431*28e138c6SAndroid Build Coastguard Worker          if (jitter->destroy)
432*28e138c6SAndroid Build Coastguard Worker             jitter->destroy(jitter->packets[i].data);
433*28e138c6SAndroid Build Coastguard Worker          else
434*28e138c6SAndroid Build Coastguard Worker             speex_free(jitter->packets[i].data);
435*28e138c6SAndroid Build Coastguard Worker          jitter->packets[i].data=NULL;
436*28e138c6SAndroid Build Coastguard Worker          /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
437*28e138c6SAndroid Build Coastguard Worker       }
438*28e138c6SAndroid Build Coastguard Worker 
439*28e138c6SAndroid Build Coastguard Worker       /* Copy packet in buffer */
440*28e138c6SAndroid Build Coastguard Worker       if (jitter->destroy)
441*28e138c6SAndroid Build Coastguard Worker       {
442*28e138c6SAndroid Build Coastguard Worker          jitter->packets[i].data = packet->data;
443*28e138c6SAndroid Build Coastguard Worker       } else {
444*28e138c6SAndroid Build Coastguard Worker          jitter->packets[i].data=(char*)speex_alloc(packet->len);
445*28e138c6SAndroid Build Coastguard Worker          for (j=0;j<packet->len;j++)
446*28e138c6SAndroid Build Coastguard Worker             jitter->packets[i].data[j]=packet->data[j];
447*28e138c6SAndroid Build Coastguard Worker       }
448*28e138c6SAndroid Build Coastguard Worker       jitter->packets[i].timestamp=packet->timestamp;
449*28e138c6SAndroid Build Coastguard Worker       jitter->packets[i].span=packet->span;
450*28e138c6SAndroid Build Coastguard Worker       jitter->packets[i].len=packet->len;
451*28e138c6SAndroid Build Coastguard Worker       jitter->packets[i].sequence=packet->sequence;
452*28e138c6SAndroid Build Coastguard Worker       jitter->packets[i].user_data=packet->user_data;
453*28e138c6SAndroid Build Coastguard Worker       if (jitter->reset_state || late)
454*28e138c6SAndroid Build Coastguard Worker          jitter->arrival[i] = 0;
455*28e138c6SAndroid Build Coastguard Worker       else
456*28e138c6SAndroid Build Coastguard Worker          jitter->arrival[i] = jitter->next_stop;
457*28e138c6SAndroid Build Coastguard Worker    }
458*28e138c6SAndroid Build Coastguard Worker 
459*28e138c6SAndroid Build Coastguard Worker 
460*28e138c6SAndroid Build Coastguard Worker }
461*28e138c6SAndroid Build Coastguard Worker 
462*28e138c6SAndroid Build Coastguard Worker /** Get one packet from the jitter buffer */
jitter_buffer_get(JitterBuffer * jitter,JitterBufferPacket * packet,spx_int32_t desired_span,spx_int32_t * start_offset)463*28e138c6SAndroid Build Coastguard Worker EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
464*28e138c6SAndroid Build Coastguard Worker {
465*28e138c6SAndroid Build Coastguard Worker    int i;
466*28e138c6SAndroid Build Coastguard Worker    unsigned int j;
467*28e138c6SAndroid Build Coastguard Worker    spx_int16_t opt;
468*28e138c6SAndroid Build Coastguard Worker 
469*28e138c6SAndroid Build Coastguard Worker    if (start_offset != NULL)
470*28e138c6SAndroid Build Coastguard Worker       *start_offset = 0;
471*28e138c6SAndroid Build Coastguard Worker 
472*28e138c6SAndroid Build Coastguard Worker    /* Syncing on the first call */
473*28e138c6SAndroid Build Coastguard Worker    if (jitter->reset_state)
474*28e138c6SAndroid Build Coastguard Worker    {
475*28e138c6SAndroid Build Coastguard Worker       int found = 0;
476*28e138c6SAndroid Build Coastguard Worker       /* Find the oldest packet */
477*28e138c6SAndroid Build Coastguard Worker       spx_uint32_t oldest=0;
478*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
479*28e138c6SAndroid Build Coastguard Worker       {
480*28e138c6SAndroid Build Coastguard Worker          if (jitter->packets[i].data && (!found || LT32(jitter->packets[i].timestamp,oldest)))
481*28e138c6SAndroid Build Coastguard Worker          {
482*28e138c6SAndroid Build Coastguard Worker             oldest = jitter->packets[i].timestamp;
483*28e138c6SAndroid Build Coastguard Worker             found = 1;
484*28e138c6SAndroid Build Coastguard Worker          }
485*28e138c6SAndroid Build Coastguard Worker       }
486*28e138c6SAndroid Build Coastguard Worker       if (found)
487*28e138c6SAndroid Build Coastguard Worker       {
488*28e138c6SAndroid Build Coastguard Worker          jitter->reset_state=0;
489*28e138c6SAndroid Build Coastguard Worker          jitter->pointer_timestamp = oldest;
490*28e138c6SAndroid Build Coastguard Worker          jitter->next_stop = oldest;
491*28e138c6SAndroid Build Coastguard Worker       } else {
492*28e138c6SAndroid Build Coastguard Worker          packet->timestamp = 0;
493*28e138c6SAndroid Build Coastguard Worker          packet->span = jitter->interp_requested;
494*28e138c6SAndroid Build Coastguard Worker          return JITTER_BUFFER_MISSING;
495*28e138c6SAndroid Build Coastguard Worker       }
496*28e138c6SAndroid Build Coastguard Worker    }
497*28e138c6SAndroid Build Coastguard Worker 
498*28e138c6SAndroid Build Coastguard Worker 
499*28e138c6SAndroid Build Coastguard Worker    jitter->last_returned_timestamp = jitter->pointer_timestamp;
500*28e138c6SAndroid Build Coastguard Worker 
501*28e138c6SAndroid Build Coastguard Worker    if (jitter->interp_requested != 0)
502*28e138c6SAndroid Build Coastguard Worker    {
503*28e138c6SAndroid Build Coastguard Worker       packet->timestamp = jitter->pointer_timestamp;
504*28e138c6SAndroid Build Coastguard Worker       packet->span = jitter->interp_requested;
505*28e138c6SAndroid Build Coastguard Worker 
506*28e138c6SAndroid Build Coastguard Worker       /* Increment the pointer because it got decremented in the delay update */
507*28e138c6SAndroid Build Coastguard Worker       jitter->pointer_timestamp += jitter->interp_requested;
508*28e138c6SAndroid Build Coastguard Worker       packet->len = 0;
509*28e138c6SAndroid Build Coastguard Worker       /*fprintf (stderr, "Deferred interpolate\n");*/
510*28e138c6SAndroid Build Coastguard Worker 
511*28e138c6SAndroid Build Coastguard Worker       jitter->interp_requested = 0;
512*28e138c6SAndroid Build Coastguard Worker 
513*28e138c6SAndroid Build Coastguard Worker       jitter->buffered = packet->span - desired_span;
514*28e138c6SAndroid Build Coastguard Worker 
515*28e138c6SAndroid Build Coastguard Worker       return JITTER_BUFFER_INSERTION;
516*28e138c6SAndroid Build Coastguard Worker    }
517*28e138c6SAndroid Build Coastguard Worker 
518*28e138c6SAndroid Build Coastguard Worker    /* Searching for the packet that fits best */
519*28e138c6SAndroid Build Coastguard Worker 
520*28e138c6SAndroid Build Coastguard Worker    /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */
521*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
522*28e138c6SAndroid Build Coastguard Worker    {
523*28e138c6SAndroid Build Coastguard Worker       if (jitter->packets[i].data && jitter->packets[i].timestamp==jitter->pointer_timestamp && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span))
524*28e138c6SAndroid Build Coastguard Worker          break;
525*28e138c6SAndroid Build Coastguard Worker    }
526*28e138c6SAndroid Build Coastguard Worker 
527*28e138c6SAndroid Build Coastguard Worker    /* If no match, try for an "older" packet that still spans (fully) the current chunk */
528*28e138c6SAndroid Build Coastguard Worker    if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
529*28e138c6SAndroid Build Coastguard Worker    {
530*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
531*28e138c6SAndroid Build Coastguard Worker       {
532*28e138c6SAndroid Build Coastguard Worker          if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span))
533*28e138c6SAndroid Build Coastguard Worker             break;
534*28e138c6SAndroid Build Coastguard Worker       }
535*28e138c6SAndroid Build Coastguard Worker    }
536*28e138c6SAndroid Build Coastguard Worker 
537*28e138c6SAndroid Build Coastguard Worker    /* If still no match, try for an "older" packet that spans part of the current chunk */
538*28e138c6SAndroid Build Coastguard Worker    if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
539*28e138c6SAndroid Build Coastguard Worker    {
540*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
541*28e138c6SAndroid Build Coastguard Worker       {
542*28e138c6SAndroid Build Coastguard Worker          if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GT32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp))
543*28e138c6SAndroid Build Coastguard Worker             break;
544*28e138c6SAndroid Build Coastguard Worker       }
545*28e138c6SAndroid Build Coastguard Worker    }
546*28e138c6SAndroid Build Coastguard Worker 
547*28e138c6SAndroid Build Coastguard Worker    /* If still no match, try for earliest packet possible */
548*28e138c6SAndroid Build Coastguard Worker    if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
549*28e138c6SAndroid Build Coastguard Worker    {
550*28e138c6SAndroid Build Coastguard Worker       int found = 0;
551*28e138c6SAndroid Build Coastguard Worker       spx_uint32_t best_time=0;
552*28e138c6SAndroid Build Coastguard Worker       int best_span=0;
553*28e138c6SAndroid Build Coastguard Worker       int besti=0;
554*28e138c6SAndroid Build Coastguard Worker       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
555*28e138c6SAndroid Build Coastguard Worker       {
556*28e138c6SAndroid Build Coastguard Worker          /* check if packet starts within current chunk */
557*28e138c6SAndroid Build Coastguard Worker          if (jitter->packets[i].data && LT32(jitter->packets[i].timestamp,jitter->pointer_timestamp+desired_span) && GE32(jitter->packets[i].timestamp,jitter->pointer_timestamp))
558*28e138c6SAndroid Build Coastguard Worker          {
559*28e138c6SAndroid Build Coastguard Worker             if (!found || LT32(jitter->packets[i].timestamp,best_time) || (jitter->packets[i].timestamp==best_time && GT32(jitter->packets[i].span,best_span)))
560*28e138c6SAndroid Build Coastguard Worker             {
561*28e138c6SAndroid Build Coastguard Worker                best_time = jitter->packets[i].timestamp;
562*28e138c6SAndroid Build Coastguard Worker                best_span = jitter->packets[i].span;
563*28e138c6SAndroid Build Coastguard Worker                besti = i;
564*28e138c6SAndroid Build Coastguard Worker                found = 1;
565*28e138c6SAndroid Build Coastguard Worker             }
566*28e138c6SAndroid Build Coastguard Worker          }
567*28e138c6SAndroid Build Coastguard Worker       }
568*28e138c6SAndroid Build Coastguard Worker       if (found)
569*28e138c6SAndroid Build Coastguard Worker       {
570*28e138c6SAndroid Build Coastguard Worker          i=besti;
571*28e138c6SAndroid Build Coastguard Worker          /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->packets[i].timestamp, jitter->pointer_timestamp, chunk_size, jitter->packets[i].span);*/
572*28e138c6SAndroid Build Coastguard Worker       }
573*28e138c6SAndroid Build Coastguard Worker    }
574*28e138c6SAndroid Build Coastguard Worker 
575*28e138c6SAndroid Build Coastguard Worker    /* If we find something */
576*28e138c6SAndroid Build Coastguard Worker    if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
577*28e138c6SAndroid Build Coastguard Worker    {
578*28e138c6SAndroid Build Coastguard Worker       spx_int32_t offset;
579*28e138c6SAndroid Build Coastguard Worker 
580*28e138c6SAndroid Build Coastguard Worker       /* We (obviously) haven't lost this packet */
581*28e138c6SAndroid Build Coastguard Worker       jitter->lost_count = 0;
582*28e138c6SAndroid Build Coastguard Worker 
583*28e138c6SAndroid Build Coastguard Worker       /* In this case, 0 isn't as a valid timestamp */
584*28e138c6SAndroid Build Coastguard Worker       if (jitter->arrival[i] != 0)
585*28e138c6SAndroid Build Coastguard Worker       {
586*28e138c6SAndroid Build Coastguard Worker          update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin);
587*28e138c6SAndroid Build Coastguard Worker       }
588*28e138c6SAndroid Build Coastguard Worker 
589*28e138c6SAndroid Build Coastguard Worker 
590*28e138c6SAndroid Build Coastguard Worker       /* Copy packet */
591*28e138c6SAndroid Build Coastguard Worker       if (jitter->destroy)
592*28e138c6SAndroid Build Coastguard Worker       {
593*28e138c6SAndroid Build Coastguard Worker          packet->data = jitter->packets[i].data;
594*28e138c6SAndroid Build Coastguard Worker          packet->len = jitter->packets[i].len;
595*28e138c6SAndroid Build Coastguard Worker       } else {
596*28e138c6SAndroid Build Coastguard Worker          if (jitter->packets[i].len > packet->len)
597*28e138c6SAndroid Build Coastguard Worker          {
598*28e138c6SAndroid Build Coastguard Worker             speex_warning_int("jitter_buffer_get(): packet too large to fit. Size is", jitter->packets[i].len);
599*28e138c6SAndroid Build Coastguard Worker          } else {
600*28e138c6SAndroid Build Coastguard Worker             packet->len = jitter->packets[i].len;
601*28e138c6SAndroid Build Coastguard Worker          }
602*28e138c6SAndroid Build Coastguard Worker          for (j=0;j<packet->len;j++)
603*28e138c6SAndroid Build Coastguard Worker             packet->data[j] = jitter->packets[i].data[j];
604*28e138c6SAndroid Build Coastguard Worker          /* Remove packet */
605*28e138c6SAndroid Build Coastguard Worker          speex_free(jitter->packets[i].data);
606*28e138c6SAndroid Build Coastguard Worker       }
607*28e138c6SAndroid Build Coastguard Worker       jitter->packets[i].data = NULL;
608*28e138c6SAndroid Build Coastguard Worker       /* Set timestamp and span (if requested) */
609*28e138c6SAndroid Build Coastguard Worker       offset = (spx_int32_t)jitter->packets[i].timestamp-(spx_int32_t)jitter->pointer_timestamp;
610*28e138c6SAndroid Build Coastguard Worker       if (start_offset != NULL)
611*28e138c6SAndroid Build Coastguard Worker          *start_offset = offset;
612*28e138c6SAndroid Build Coastguard Worker       else if (offset != 0)
613*28e138c6SAndroid Build Coastguard Worker          speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset);
614*28e138c6SAndroid Build Coastguard Worker 
615*28e138c6SAndroid Build Coastguard Worker       packet->timestamp = jitter->packets[i].timestamp;
616*28e138c6SAndroid Build Coastguard Worker       jitter->last_returned_timestamp = packet->timestamp;
617*28e138c6SAndroid Build Coastguard Worker 
618*28e138c6SAndroid Build Coastguard Worker       packet->span = jitter->packets[i].span;
619*28e138c6SAndroid Build Coastguard Worker       packet->sequence = jitter->packets[i].sequence;
620*28e138c6SAndroid Build Coastguard Worker       packet->user_data = jitter->packets[i].user_data;
621*28e138c6SAndroid Build Coastguard Worker       /* Point to the end of the current packet */
622*28e138c6SAndroid Build Coastguard Worker       jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span;
623*28e138c6SAndroid Build Coastguard Worker 
624*28e138c6SAndroid Build Coastguard Worker       jitter->buffered = packet->span - desired_span;
625*28e138c6SAndroid Build Coastguard Worker 
626*28e138c6SAndroid Build Coastguard Worker       if (start_offset != NULL)
627*28e138c6SAndroid Build Coastguard Worker          jitter->buffered += *start_offset;
628*28e138c6SAndroid Build Coastguard Worker 
629*28e138c6SAndroid Build Coastguard Worker       return JITTER_BUFFER_OK;
630*28e138c6SAndroid Build Coastguard Worker    }
631*28e138c6SAndroid Build Coastguard Worker 
632*28e138c6SAndroid Build Coastguard Worker 
633*28e138c6SAndroid Build Coastguard Worker    /* If we haven't found anything worth returning */
634*28e138c6SAndroid Build Coastguard Worker 
635*28e138c6SAndroid Build Coastguard Worker    /*fprintf (stderr, "not found\n");*/
636*28e138c6SAndroid Build Coastguard Worker    jitter->lost_count++;
637*28e138c6SAndroid Build Coastguard Worker    /*fprintf (stderr, "m");*/
638*28e138c6SAndroid Build Coastguard Worker    /*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/
639*28e138c6SAndroid Build Coastguard Worker 
640*28e138c6SAndroid Build Coastguard Worker    opt = compute_opt_delay(jitter);
641*28e138c6SAndroid Build Coastguard Worker 
642*28e138c6SAndroid Build Coastguard Worker    /* Should we force an increase in the buffer or just do normal interpolation? */
643*28e138c6SAndroid Build Coastguard Worker    if (opt < 0)
644*28e138c6SAndroid Build Coastguard Worker    {
645*28e138c6SAndroid Build Coastguard Worker       /* Need to increase buffering */
646*28e138c6SAndroid Build Coastguard Worker 
647*28e138c6SAndroid Build Coastguard Worker       /* Shift histogram to compensate */
648*28e138c6SAndroid Build Coastguard Worker       shift_timings(jitter, -opt);
649*28e138c6SAndroid Build Coastguard Worker 
650*28e138c6SAndroid Build Coastguard Worker       packet->timestamp = jitter->pointer_timestamp;
651*28e138c6SAndroid Build Coastguard Worker       packet->span = -opt;
652*28e138c6SAndroid Build Coastguard Worker       /* Don't move the pointer_timestamp forward */
653*28e138c6SAndroid Build Coastguard Worker       packet->len = 0;
654*28e138c6SAndroid Build Coastguard Worker 
655*28e138c6SAndroid Build Coastguard Worker       jitter->buffered = packet->span - desired_span;
656*28e138c6SAndroid Build Coastguard Worker       return JITTER_BUFFER_INSERTION;
657*28e138c6SAndroid Build Coastguard Worker       /*jitter->pointer_timestamp -= jitter->delay_step;*/
658*28e138c6SAndroid Build Coastguard Worker       /*fprintf (stderr, "Forced to interpolate\n");*/
659*28e138c6SAndroid Build Coastguard Worker    } else {
660*28e138c6SAndroid Build Coastguard Worker       /* Normal packet loss */
661*28e138c6SAndroid Build Coastguard Worker       packet->timestamp = jitter->pointer_timestamp;
662*28e138c6SAndroid Build Coastguard Worker 
663*28e138c6SAndroid Build Coastguard Worker       desired_span = ROUND_DOWN(desired_span, jitter->concealment_size);
664*28e138c6SAndroid Build Coastguard Worker       packet->span = desired_span;
665*28e138c6SAndroid Build Coastguard Worker       jitter->pointer_timestamp += desired_span;
666*28e138c6SAndroid Build Coastguard Worker       packet->len = 0;
667*28e138c6SAndroid Build Coastguard Worker 
668*28e138c6SAndroid Build Coastguard Worker       jitter->buffered = packet->span - desired_span;
669*28e138c6SAndroid Build Coastguard Worker       return JITTER_BUFFER_MISSING;
670*28e138c6SAndroid Build Coastguard Worker       /*fprintf (stderr, "Normal loss\n");*/
671*28e138c6SAndroid Build Coastguard Worker    }
672*28e138c6SAndroid Build Coastguard Worker 
673*28e138c6SAndroid Build Coastguard Worker 
674*28e138c6SAndroid Build Coastguard Worker }
675*28e138c6SAndroid Build Coastguard Worker 
jitter_buffer_get_another(JitterBuffer * jitter,JitterBufferPacket * packet)676*28e138c6SAndroid Build Coastguard Worker EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
677*28e138c6SAndroid Build Coastguard Worker {
678*28e138c6SAndroid Build Coastguard Worker    int i, j;
679*28e138c6SAndroid Build Coastguard Worker    for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
680*28e138c6SAndroid Build Coastguard Worker    {
681*28e138c6SAndroid Build Coastguard Worker       if (jitter->packets[i].data && jitter->packets[i].timestamp==jitter->last_returned_timestamp)
682*28e138c6SAndroid Build Coastguard Worker          break;
683*28e138c6SAndroid Build Coastguard Worker    }
684*28e138c6SAndroid Build Coastguard Worker    if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
685*28e138c6SAndroid Build Coastguard Worker    {
686*28e138c6SAndroid Build Coastguard Worker       /* Copy packet */
687*28e138c6SAndroid Build Coastguard Worker       packet->len = jitter->packets[i].len;
688*28e138c6SAndroid Build Coastguard Worker       if (jitter->destroy)
689*28e138c6SAndroid Build Coastguard Worker       {
690*28e138c6SAndroid Build Coastguard Worker          packet->data = jitter->packets[i].data;
691*28e138c6SAndroid Build Coastguard Worker       } else {
692*28e138c6SAndroid Build Coastguard Worker          for (j=0;j<packet->len;j++)
693*28e138c6SAndroid Build Coastguard Worker             packet->data[j] = jitter->packets[i].data[j];
694*28e138c6SAndroid Build Coastguard Worker          /* Remove packet */
695*28e138c6SAndroid Build Coastguard Worker          speex_free(jitter->packets[i].data);
696*28e138c6SAndroid Build Coastguard Worker       }
697*28e138c6SAndroid Build Coastguard Worker       jitter->packets[i].data = NULL;
698*28e138c6SAndroid Build Coastguard Worker       packet->timestamp = jitter->packets[i].timestamp;
699*28e138c6SAndroid Build Coastguard Worker       packet->span = jitter->packets[i].span;
700*28e138c6SAndroid Build Coastguard Worker       packet->sequence = jitter->packets[i].sequence;
701*28e138c6SAndroid Build Coastguard Worker       packet->user_data = jitter->packets[i].user_data;
702*28e138c6SAndroid Build Coastguard Worker       return JITTER_BUFFER_OK;
703*28e138c6SAndroid Build Coastguard Worker    } else {
704*28e138c6SAndroid Build Coastguard Worker       packet->data = NULL;
705*28e138c6SAndroid Build Coastguard Worker       packet->len = 0;
706*28e138c6SAndroid Build Coastguard Worker       packet->span = 0;
707*28e138c6SAndroid Build Coastguard Worker       return JITTER_BUFFER_MISSING;
708*28e138c6SAndroid Build Coastguard Worker    }
709*28e138c6SAndroid Build Coastguard Worker }
710*28e138c6SAndroid Build Coastguard Worker 
711*28e138c6SAndroid Build Coastguard Worker /* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
_jitter_buffer_update_delay(JitterBuffer * jitter,JitterBufferPacket * packet,spx_int32_t * start_offset)712*28e138c6SAndroid Build Coastguard Worker static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
713*28e138c6SAndroid Build Coastguard Worker {
714*28e138c6SAndroid Build Coastguard Worker    spx_int16_t opt = compute_opt_delay(jitter);
715*28e138c6SAndroid Build Coastguard Worker    /*fprintf(stderr, "opt adjustment is %d ", opt);*/
716*28e138c6SAndroid Build Coastguard Worker 
717*28e138c6SAndroid Build Coastguard Worker    if (opt < 0)
718*28e138c6SAndroid Build Coastguard Worker    {
719*28e138c6SAndroid Build Coastguard Worker       shift_timings(jitter, -opt);
720*28e138c6SAndroid Build Coastguard Worker 
721*28e138c6SAndroid Build Coastguard Worker       jitter->pointer_timestamp += opt;
722*28e138c6SAndroid Build Coastguard Worker       jitter->interp_requested = -opt;
723*28e138c6SAndroid Build Coastguard Worker       /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/
724*28e138c6SAndroid Build Coastguard Worker    } else if (opt > 0)
725*28e138c6SAndroid Build Coastguard Worker    {
726*28e138c6SAndroid Build Coastguard Worker       shift_timings(jitter, -opt);
727*28e138c6SAndroid Build Coastguard Worker       jitter->pointer_timestamp += opt;
728*28e138c6SAndroid Build Coastguard Worker       /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/
729*28e138c6SAndroid Build Coastguard Worker    }
730*28e138c6SAndroid Build Coastguard Worker 
731*28e138c6SAndroid Build Coastguard Worker    return opt;
732*28e138c6SAndroid Build Coastguard Worker }
733*28e138c6SAndroid Build Coastguard Worker 
734*28e138c6SAndroid Build Coastguard Worker /* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
jitter_buffer_update_delay(JitterBuffer * jitter,JitterBufferPacket * packet,spx_int32_t * start_offset)735*28e138c6SAndroid Build Coastguard Worker EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
736*28e138c6SAndroid Build Coastguard Worker {
737*28e138c6SAndroid Build Coastguard Worker    /* If the programmer calls jitter_buffer_update_delay() directly,
738*28e138c6SAndroid Build Coastguard Worker       automatically disable auto-adjustment */
739*28e138c6SAndroid Build Coastguard Worker    jitter->auto_adjust = 0;
740*28e138c6SAndroid Build Coastguard Worker 
741*28e138c6SAndroid Build Coastguard Worker    return _jitter_buffer_update_delay(jitter, packet, start_offset);
742*28e138c6SAndroid Build Coastguard Worker }
743*28e138c6SAndroid Build Coastguard Worker 
744*28e138c6SAndroid Build Coastguard Worker /** Get pointer timestamp of jitter buffer */
jitter_buffer_get_pointer_timestamp(JitterBuffer * jitter)745*28e138c6SAndroid Build Coastguard Worker EXPORT int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
746*28e138c6SAndroid Build Coastguard Worker {
747*28e138c6SAndroid Build Coastguard Worker    return jitter->pointer_timestamp;
748*28e138c6SAndroid Build Coastguard Worker }
749*28e138c6SAndroid Build Coastguard Worker 
jitter_buffer_tick(JitterBuffer * jitter)750*28e138c6SAndroid Build Coastguard Worker EXPORT void jitter_buffer_tick(JitterBuffer *jitter)
751*28e138c6SAndroid Build Coastguard Worker {
752*28e138c6SAndroid Build Coastguard Worker    /* Automatically-adjust the buffering delay if requested */
753*28e138c6SAndroid Build Coastguard Worker    if (jitter->auto_adjust)
754*28e138c6SAndroid Build Coastguard Worker       _jitter_buffer_update_delay(jitter, NULL, NULL);
755*28e138c6SAndroid Build Coastguard Worker 
756*28e138c6SAndroid Build Coastguard Worker    if (jitter->buffered >= 0)
757*28e138c6SAndroid Build Coastguard Worker    {
758*28e138c6SAndroid Build Coastguard Worker       jitter->next_stop = jitter->pointer_timestamp - jitter->buffered;
759*28e138c6SAndroid Build Coastguard Worker    } else {
760*28e138c6SAndroid Build Coastguard Worker       jitter->next_stop = jitter->pointer_timestamp;
761*28e138c6SAndroid Build Coastguard Worker       speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered);
762*28e138c6SAndroid Build Coastguard Worker    }
763*28e138c6SAndroid Build Coastguard Worker    jitter->buffered = 0;
764*28e138c6SAndroid Build Coastguard Worker }
765*28e138c6SAndroid Build Coastguard Worker 
jitter_buffer_remaining_span(JitterBuffer * jitter,spx_uint32_t rem)766*28e138c6SAndroid Build Coastguard Worker EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
767*28e138c6SAndroid Build Coastguard Worker {
768*28e138c6SAndroid Build Coastguard Worker    /* Automatically-adjust the buffering delay if requested */
769*28e138c6SAndroid Build Coastguard Worker    if (jitter->auto_adjust)
770*28e138c6SAndroid Build Coastguard Worker       _jitter_buffer_update_delay(jitter, NULL, NULL);
771*28e138c6SAndroid Build Coastguard Worker 
772*28e138c6SAndroid Build Coastguard Worker    if (jitter->buffered < 0)
773*28e138c6SAndroid Build Coastguard Worker       speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered);
774*28e138c6SAndroid Build Coastguard Worker    jitter->next_stop = jitter->pointer_timestamp - rem;
775*28e138c6SAndroid Build Coastguard Worker }
776*28e138c6SAndroid Build Coastguard Worker 
777*28e138c6SAndroid Build Coastguard Worker 
778*28e138c6SAndroid Build Coastguard Worker /* Used like the ioctl function to control the jitter buffer parameters */
jitter_buffer_ctl(JitterBuffer * jitter,int request,void * ptr)779*28e138c6SAndroid Build Coastguard Worker EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
780*28e138c6SAndroid Build Coastguard Worker {
781*28e138c6SAndroid Build Coastguard Worker    int count, i;
782*28e138c6SAndroid Build Coastguard Worker    switch(request)
783*28e138c6SAndroid Build Coastguard Worker    {
784*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_SET_MARGIN:
785*28e138c6SAndroid Build Coastguard Worker          jitter->buffer_margin = *(spx_int32_t*)ptr;
786*28e138c6SAndroid Build Coastguard Worker          break;
787*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_GET_MARGIN:
788*28e138c6SAndroid Build Coastguard Worker          *(spx_int32_t*)ptr = jitter->buffer_margin;
789*28e138c6SAndroid Build Coastguard Worker          break;
790*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_GET_AVALIABLE_COUNT:
791*28e138c6SAndroid Build Coastguard Worker          count = 0;
792*28e138c6SAndroid Build Coastguard Worker          for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
793*28e138c6SAndroid Build Coastguard Worker          {
794*28e138c6SAndroid Build Coastguard Worker             if (jitter->packets[i].data && LE32(jitter->pointer_timestamp, jitter->packets[i].timestamp))
795*28e138c6SAndroid Build Coastguard Worker             {
796*28e138c6SAndroid Build Coastguard Worker                count++;
797*28e138c6SAndroid Build Coastguard Worker             }
798*28e138c6SAndroid Build Coastguard Worker          }
799*28e138c6SAndroid Build Coastguard Worker          *(spx_int32_t*)ptr = count;
800*28e138c6SAndroid Build Coastguard Worker          break;
801*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_SET_DESTROY_CALLBACK:
802*28e138c6SAndroid Build Coastguard Worker          jitter->destroy = (void (*) (void *))ptr;
803*28e138c6SAndroid Build Coastguard Worker          break;
804*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_GET_DESTROY_CALLBACK:
805*28e138c6SAndroid Build Coastguard Worker          *(void (**) (void *))ptr = jitter->destroy;
806*28e138c6SAndroid Build Coastguard Worker          break;
807*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_SET_DELAY_STEP:
808*28e138c6SAndroid Build Coastguard Worker          jitter->delay_step = *(spx_int32_t*)ptr;
809*28e138c6SAndroid Build Coastguard Worker          break;
810*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_GET_DELAY_STEP:
811*28e138c6SAndroid Build Coastguard Worker          *(spx_int32_t*)ptr = jitter->delay_step;
812*28e138c6SAndroid Build Coastguard Worker          break;
813*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_SET_CONCEALMENT_SIZE:
814*28e138c6SAndroid Build Coastguard Worker          jitter->concealment_size = *(spx_int32_t*)ptr;
815*28e138c6SAndroid Build Coastguard Worker          break;
816*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_GET_CONCEALMENT_SIZE:
817*28e138c6SAndroid Build Coastguard Worker          *(spx_int32_t*)ptr = jitter->concealment_size;
818*28e138c6SAndroid Build Coastguard Worker          break;
819*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_SET_MAX_LATE_RATE:
820*28e138c6SAndroid Build Coastguard Worker          jitter->max_late_rate = *(spx_int32_t*)ptr;
821*28e138c6SAndroid Build Coastguard Worker          jitter->window_size = 100*TOP_DELAY/jitter->max_late_rate;
822*28e138c6SAndroid Build Coastguard Worker          jitter->subwindow_size = jitter->window_size/MAX_BUFFERS;
823*28e138c6SAndroid Build Coastguard Worker          break;
824*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_GET_MAX_LATE_RATE:
825*28e138c6SAndroid Build Coastguard Worker          *(spx_int32_t*)ptr = jitter->max_late_rate;
826*28e138c6SAndroid Build Coastguard Worker          break;
827*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_SET_LATE_COST:
828*28e138c6SAndroid Build Coastguard Worker          jitter->latency_tradeoff = *(spx_int32_t*)ptr;
829*28e138c6SAndroid Build Coastguard Worker          break;
830*28e138c6SAndroid Build Coastguard Worker       case JITTER_BUFFER_GET_LATE_COST:
831*28e138c6SAndroid Build Coastguard Worker          *(spx_int32_t*)ptr = jitter->latency_tradeoff;
832*28e138c6SAndroid Build Coastguard Worker          break;
833*28e138c6SAndroid Build Coastguard Worker       default:
834*28e138c6SAndroid Build Coastguard Worker          speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
835*28e138c6SAndroid Build Coastguard Worker          return -1;
836*28e138c6SAndroid Build Coastguard Worker    }
837*28e138c6SAndroid Build Coastguard Worker    return 0;
838*28e138c6SAndroid Build Coastguard Worker }
839*28e138c6SAndroid Build Coastguard Worker 
840